@wix/himalaya-cli 0.1068.0 → 0.1070.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +718 -482
- package/guides/headless-loop.md +9 -4
- package/guides/skill.md +11 -3
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -484,6 +484,36 @@ var init_ownership = __esm({
|
|
|
484
484
|
}
|
|
485
485
|
});
|
|
486
486
|
|
|
487
|
+
// ../../core/serve-storage/src/wip-pointer.ts
|
|
488
|
+
function wipSupported(store) {
|
|
489
|
+
if (!store.getWipRecord || !store.updateWipRecord) return false;
|
|
490
|
+
return store.supportsWip ? store.supportsWip() : true;
|
|
491
|
+
}
|
|
492
|
+
function normalizeWipRecord(value) {
|
|
493
|
+
if (!value || typeof value !== "object") return { wip: null, promoted: [], evictedBefore: null };
|
|
494
|
+
const v = value;
|
|
495
|
+
const wip = v.wip && typeof v.wip.releaseId === "string" ? v.wip : null;
|
|
496
|
+
const promoted = (Array.isArray(v.promoted) ? v.promoted : []).flatMap((entry) => {
|
|
497
|
+
if (typeof entry === "string") return [{ id: entry, at: null }];
|
|
498
|
+
const e = entry;
|
|
499
|
+
return e && typeof e.id === "string" ? [{ id: e.id, at: storedTime(e.at) }] : [];
|
|
500
|
+
});
|
|
501
|
+
return { wip, promoted, evictedBefore: storedTime(v.evictedBefore) };
|
|
502
|
+
}
|
|
503
|
+
async function readWip(store, app) {
|
|
504
|
+
if (!wipSupported(store)) return "unsupported";
|
|
505
|
+
const { wip, promoted } = normalizeWipRecord(await store.getWipRecord(app));
|
|
506
|
+
if (!wip || promoted.some((p) => p.id === wip.releaseId)) return null;
|
|
507
|
+
const live2 = await store.getManifest(app);
|
|
508
|
+
return live2?.releaseId === wip.releaseId ? null : wip;
|
|
509
|
+
}
|
|
510
|
+
var storedTime;
|
|
511
|
+
var init_wip_pointer = __esm({
|
|
512
|
+
"../../core/serve-storage/src/wip-pointer.ts"() {
|
|
513
|
+
storedTime = (value) => typeof value === "string" && !Number.isNaN(Date.parse(value)) ? value : null;
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
|
|
487
517
|
// ../../core/serve-storage/src/store.ts
|
|
488
518
|
function validateFunctionManifest(manifest) {
|
|
489
519
|
const dataErrors = validateDataResources(manifest.functionDataResources, manifest.app).filter((issue2) => issue2.severity === "error");
|
|
@@ -526,6 +556,14 @@ async function retainedReleaseRefs(store, app, keepRecent = 20, keepReleaseIds =
|
|
|
526
556
|
}
|
|
527
557
|
}
|
|
528
558
|
}
|
|
559
|
+
const offered = await readWip(store, app);
|
|
560
|
+
if (offered && offered !== "unsupported" && !loaded.has(offered.releaseId) && store.getManifestById) {
|
|
561
|
+
const m = await store.getManifestById(app, offered.releaseId);
|
|
562
|
+
if (m) {
|
|
563
|
+
manifests.push(m);
|
|
564
|
+
loaded.add(m.releaseId);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
529
567
|
for (const releaseId of new Set(keepReleaseIds)) {
|
|
530
568
|
if (loaded.has(releaseId)) continue;
|
|
531
569
|
if (!store.getManifestById) throw new Error(`cannot retain function job release ${releaseId}: versioned manifest lookup is unsupported`);
|
|
@@ -554,6 +592,7 @@ var TEMPLATE_APP_PREFIX;
|
|
|
554
592
|
var init_store = __esm({
|
|
555
593
|
"../../core/serve-storage/src/store.ts"() {
|
|
556
594
|
init_ownership();
|
|
595
|
+
init_wip_pointer();
|
|
557
596
|
TEMPLATE_APP_PREFIX = "himi-template-";
|
|
558
597
|
}
|
|
559
598
|
});
|
|
@@ -764,34 +803,28 @@ var init_file_store = __esm({
|
|
|
764
803
|
else ledger.push(entry);
|
|
765
804
|
writeFileSync2(this.ledgerPath(app), JSON.stringify(ledger, null, 2));
|
|
766
805
|
}
|
|
767
|
-
// ---- RFC 0061 §3.1 owner-follow `wip`
|
|
768
|
-
// Inside the app directory, so `remove` and `reset` take it with the app. `
|
|
769
|
-
// for the way this backend is deployed — ONE writer process (serve-control; serve only
|
|
770
|
-
// the read,
|
|
806
|
+
// ---- RFC 0061 §3.1 owner-follow `wip` record ----
|
|
807
|
+
// Inside the app directory, so `remove` and `reset` take it with the app. `updateWipRecord` is a
|
|
808
|
+
// CAS for the way this backend is deployed — ONE writer process (serve-control; serve only
|
|
809
|
+
// reads): the read, `fn` and write below are synchronous with no await between them, so no other
|
|
771
810
|
// request in that process can land in the middle. It is not a cross-process lock.
|
|
772
|
-
wipPath(app) {
|
|
773
|
-
return join2(this.appDir(app), "_wip.json");
|
|
774
|
-
}
|
|
775
811
|
readWipSync(app) {
|
|
776
812
|
const b = this.read(app, "_wip.json");
|
|
777
813
|
if (!b) return null;
|
|
778
814
|
try {
|
|
779
|
-
|
|
780
|
-
return wip && typeof wip.releaseId === "string" ? wip : null;
|
|
815
|
+
return JSON.parse(b.toString("utf8"));
|
|
781
816
|
} catch {
|
|
782
817
|
return null;
|
|
783
818
|
}
|
|
784
819
|
}
|
|
785
|
-
async
|
|
786
|
-
mkdirSync2(this.appDir(app), { recursive: true });
|
|
787
|
-
writeFileSync2(this.wipPath(app), JSON.stringify(wip, null, 2));
|
|
788
|
-
}
|
|
789
|
-
async getWip(app) {
|
|
820
|
+
async getWipRecord(app) {
|
|
790
821
|
return this.readWipSync(app);
|
|
791
822
|
}
|
|
792
|
-
async
|
|
793
|
-
|
|
794
|
-
|
|
823
|
+
async updateWipRecord(app, fn) {
|
|
824
|
+
const next = fn(this.readWipSync(app));
|
|
825
|
+
if (next === void 0) return false;
|
|
826
|
+
mkdirSync2(this.appDir(app), { recursive: true });
|
|
827
|
+
writeFileSync2(join2(this.appDir(app), "_wip.json"), JSON.stringify(next, null, 2));
|
|
795
828
|
return true;
|
|
796
829
|
}
|
|
797
830
|
bundleUrl(_app, sha2565) {
|
|
@@ -3924,8 +3957,8 @@ function committedProvisioningPath(name) {
|
|
|
3924
3957
|
function committedShellFor(path2) {
|
|
3925
3958
|
const normalized = path2.replace(/\\/g, "/");
|
|
3926
3959
|
return SHELL_NAMES2.find((name) => {
|
|
3927
|
-
const
|
|
3928
|
-
return normalized ===
|
|
3960
|
+
const relative13 = committedProvisioningPath(name);
|
|
3961
|
+
return normalized === relative13 || normalized.endsWith(`/${relative13}`);
|
|
3929
3962
|
});
|
|
3930
3963
|
}
|
|
3931
3964
|
function isBrandable(repoRoot2, name) {
|
|
@@ -17387,15 +17420,20 @@ var init_gen_native_config = __esm({
|
|
|
17387
17420
|
// src/progress.ts
|
|
17388
17421
|
var progress_exports = {};
|
|
17389
17422
|
__export(progress_exports, {
|
|
17423
|
+
AGENT_WINS_WITHIN_MS: () => AGENT_WINS_WITHIN_MS,
|
|
17390
17424
|
APPROVALS_FILE: () => APPROVALS_FILE,
|
|
17391
17425
|
APPROVAL_GATES: () => APPROVAL_GATES,
|
|
17426
|
+
AUTO_MILESTONES: () => AUTO_MILESTONES,
|
|
17427
|
+
CLI_AUTHOR: () => CLI_AUTHOR,
|
|
17392
17428
|
HISTORY_DIR: () => HISTORY_DIR,
|
|
17393
17429
|
JOURNEY_STEPS: () => JOURNEY_STEPS,
|
|
17394
17430
|
MAX_IMAGE_BYTES: () => MAX_IMAGE_BYTES,
|
|
17395
17431
|
MAX_MESSAGE_CHARS: () => MAX_MESSAGE_CHARS,
|
|
17432
|
+
MILESTONE_STEP: () => MILESTONE_STEP,
|
|
17396
17433
|
PROGRESS_FILE: () => PROGRESS_FILE,
|
|
17397
17434
|
ProgressError: () => ProgressError,
|
|
17398
17435
|
UnsafeHimiDirError: () => UnsafeHimiDirError,
|
|
17436
|
+
agentCovers: () => agentCovers,
|
|
17399
17437
|
appLabel: () => appLabel,
|
|
17400
17438
|
appendApproval: () => appendApproval,
|
|
17401
17439
|
appendProgress: () => appendProgress,
|
|
@@ -17405,7 +17443,10 @@ __export(progress_exports, {
|
|
|
17405
17443
|
carryPlanningJournal: () => carryPlanningJournal,
|
|
17406
17444
|
formatBrief: () => formatBrief,
|
|
17407
17445
|
imageExtension: () => imageExtension,
|
|
17446
|
+
isCliEntry: () => isCliEntry,
|
|
17447
|
+
journalMilestone: () => journalMilestone,
|
|
17408
17448
|
journalPath: () => journalPath,
|
|
17449
|
+
looksSecret: () => looksSecret,
|
|
17409
17450
|
notifyDesktop: () => notifyDesktop,
|
|
17410
17451
|
openApprovals: () => openApprovals,
|
|
17411
17452
|
parseApprovalRef: () => parseApprovalRef,
|
|
@@ -17415,13 +17456,26 @@ __export(progress_exports, {
|
|
|
17415
17456
|
readProgress: () => readProgress,
|
|
17416
17457
|
realDirIn: () => realDirIn,
|
|
17417
17458
|
summarizeProgress: () => summarizeProgress,
|
|
17459
|
+
visibleEntries: () => visibleEntries,
|
|
17418
17460
|
writeFileAtomic: () => writeFileAtomic
|
|
17419
17461
|
});
|
|
17420
17462
|
import { spawn as spawn3 } from "node:child_process";
|
|
17421
17463
|
import { createHash as createHash8 } from "node:crypto";
|
|
17422
17464
|
import { randomUUID } from "node:crypto";
|
|
17423
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";
|
|
17424
|
-
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
|
+
}
|
|
17425
17479
|
function parseStep(raw) {
|
|
17426
17480
|
const v = raw.trim().toLowerCase();
|
|
17427
17481
|
if (/^[1-8]$/.test(v)) return JOURNEY_STEPS[Number(v) - 1];
|
|
@@ -17510,12 +17564,13 @@ function appendProgress(dir, input) {
|
|
|
17510
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`
|
|
17511
17565
|
);
|
|
17512
17566
|
}
|
|
17513
|
-
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);
|
|
17514
17568
|
const entry = {
|
|
17515
17569
|
ts: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
17516
17570
|
message,
|
|
17517
17571
|
...input.step ? { step: input.step, stepNumber: JOURNEY_STEPS.indexOf(input.step) + 1 } : {},
|
|
17518
|
-
...images.length ? { images } : {}
|
|
17572
|
+
...images.length ? { images } : {},
|
|
17573
|
+
...input.auto ? { by: CLI_AUTHOR, milestone: input.auto.milestone, ...input.auto.ref ? { ref: input.auto.ref } : {} } : {}
|
|
17519
17574
|
};
|
|
17520
17575
|
if (!realDirIn(dir, ".himi")) throw new ProgressError("unsafe_himi_dir", new UnsafeHimiDirError(".himi").message);
|
|
17521
17576
|
const file = join30(dir, PROGRESS_FILE);
|
|
@@ -17524,6 +17579,10 @@ function appendProgress(dir, input) {
|
|
|
17524
17579
|
`);
|
|
17525
17580
|
return entry;
|
|
17526
17581
|
}
|
|
17582
|
+
function packageRelative(dir, p) {
|
|
17583
|
+
const rel = relative5(dir, resolve19(p));
|
|
17584
|
+
return rel && !rel.startsWith("..") && !isAbsolute3(rel) ? toPosix(rel) : p;
|
|
17585
|
+
}
|
|
17527
17586
|
function endsWithNewline(file) {
|
|
17528
17587
|
if (!existsSync27(file)) return true;
|
|
17529
17588
|
const size = statSync5(file).size;
|
|
@@ -17542,7 +17601,7 @@ function isEntry(v) {
|
|
|
17542
17601
|
const e = v;
|
|
17543
17602
|
return typeof e.ts === "string" && typeof e.message === "string";
|
|
17544
17603
|
}
|
|
17545
|
-
function readProgress(dir) {
|
|
17604
|
+
function readProgress(dir, opts = {}) {
|
|
17546
17605
|
const file = join30(dir, PROGRESS_FILE);
|
|
17547
17606
|
if (!existsSync27(file)) return { entries: [], skipped: 0 };
|
|
17548
17607
|
const entries = [];
|
|
@@ -17557,7 +17616,34 @@ function readProgress(dir) {
|
|
|
17557
17616
|
skipped++;
|
|
17558
17617
|
}
|
|
17559
17618
|
}
|
|
17560
|
-
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
|
+
}
|
|
17561
17647
|
}
|
|
17562
17648
|
function parseGate(raw) {
|
|
17563
17649
|
const v = raw.trim().toLowerCase();
|
|
@@ -17688,7 +17774,7 @@ function formatBrief(input) {
|
|
|
17688
17774
|
if (summary.last) lines.push(`Last postcard (${minute(summary.last.ts)}): ${summary.last.message}`);
|
|
17689
17775
|
const pastPlan = (summary.current?.stepNumber ?? 0) > JOURNEY_STEPS.indexOf("plan") + 1;
|
|
17690
17776
|
lines.push(
|
|
17691
|
-
!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.`
|
|
17692
17778
|
);
|
|
17693
17779
|
}
|
|
17694
17780
|
if (open.length) {
|
|
@@ -17702,7 +17788,7 @@ function formatBrief(input) {
|
|
|
17702
17788
|
}
|
|
17703
17789
|
function summarizeProgress(entries) {
|
|
17704
17790
|
if (!entries.length) return { count: 0 };
|
|
17705
|
-
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));
|
|
17706
17792
|
const first = entries[0];
|
|
17707
17793
|
const last = entries[entries.length - 1];
|
|
17708
17794
|
const elapsed = Date.parse(last.ts) - Date.parse(first.ts);
|
|
@@ -17763,10 +17849,16 @@ function journalPath(dir) {
|
|
|
17763
17849
|
const rel = relative5(process.cwd(), abs);
|
|
17764
17850
|
return rel && !rel.startsWith("..") ? rel : abs;
|
|
17765
17851
|
}
|
|
17766
|
-
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;
|
|
17767
17853
|
var init_progress = __esm({
|
|
17768
17854
|
"src/progress.ts"() {
|
|
17769
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] : []) : []);
|
|
17770
17862
|
PROGRESS_FILE = join30(".himi", "progress.jsonl");
|
|
17771
17863
|
HISTORY_DIR = join30(".himi", "history");
|
|
17772
17864
|
APPROVALS_FILE = join30(".himi", "approvals.jsonl");
|
|
@@ -17793,6 +17885,17 @@ var init_progress = __esm({
|
|
|
17793
17885
|
super(`${rel} is not a real directory inside the content package (a symlink?) \u2014 refusing to write through it`);
|
|
17794
17886
|
}
|
|
17795
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}$/;
|
|
17796
17899
|
gateLabel = (gate) => APPROVAL_GATES.find((g) => g.id === gate)?.label ?? gate;
|
|
17797
17900
|
minute = (iso) => `${iso.slice(0, 16).replace("T", " ")} UTC`;
|
|
17798
17901
|
NOTIFY_TIMEOUT_MS = 3e3;
|
|
@@ -17861,9 +17964,9 @@ ${after}`;
|
|
|
17861
17964
|
function blockVersion(text5) {
|
|
17862
17965
|
return STAMP_RE.exec(text5)?.[1] ?? null;
|
|
17863
17966
|
}
|
|
17864
|
-
function agentsMdBody(
|
|
17967
|
+
function agentsMdBody(appName2) {
|
|
17865
17968
|
const gates = APPROVAL_GATES.map((g) => `- \`${g.id}\` \u2014 ${g.label}`).join("\n");
|
|
17866
|
-
return `# ${
|
|
17969
|
+
return `# ${appName2 ? `${appName2} \u2014 a Himalaya app` : "A Himalaya app"}
|
|
17867
17970
|
|
|
17868
17971
|
This folder is a Himalaya content package: a native iOS / Android / web app whose screens are data
|
|
17869
17972
|
(JSON descriptors) plus small JavaScript workers, built and shipped with the \`himi\` CLI
|
|
@@ -18924,9 +19027,9 @@ var init_store2 = __esm({
|
|
|
18924
19027
|
Store = class {
|
|
18925
19028
|
_db;
|
|
18926
19029
|
dbPath;
|
|
18927
|
-
constructor(
|
|
19030
|
+
constructor(appName2) {
|
|
18928
19031
|
const dataRoot = process.env.HIMALAYA_DEV_STORE_DIR ? resolve23(process.env.HIMALAYA_DEV_STORE_DIR) : resolve23(ROOT3, "core/dev-server/data");
|
|
18929
|
-
this.dbPath = resolve23(dataRoot, `${
|
|
19032
|
+
this.dbPath = resolve23(dataRoot, `${appName2}.sqlite`);
|
|
18930
19033
|
}
|
|
18931
19034
|
/** The node:sqlite handle — opened, bootstrapped, and seeded on first access. */
|
|
18932
19035
|
get db() {
|
|
@@ -21651,8 +21754,8 @@ var init_net_mocks_rollover = __esm({
|
|
|
21651
21754
|
});
|
|
21652
21755
|
|
|
21653
21756
|
// ../../core/dev-server/src/player-proxy.ts
|
|
21654
|
-
function isPlayerHost(
|
|
21655
|
-
return
|
|
21757
|
+
function isPlayerHost(appName2) {
|
|
21758
|
+
return appName2 === PLAYER_APP_ID || process.env.HIMALAYA_DEV_MULTI_APP === "1";
|
|
21656
21759
|
}
|
|
21657
21760
|
function resolveServeBase() {
|
|
21658
21761
|
const override = process.env.HIMALAYA_PLAYER_SERVE_URL;
|
|
@@ -22900,6 +23003,7 @@ function shouldRevealError(args) {
|
|
|
22900
23003
|
var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
|
|
22901
23004
|
var init_validation = __esm({
|
|
22902
23005
|
"../../core/ts/src/validation.ts"() {
|
|
23006
|
+
"use strict";
|
|
22903
23007
|
EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
22904
23008
|
URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
22905
23009
|
INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
@@ -26500,6 +26604,7 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
|
|
|
26500
26604
|
var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
|
|
26501
26605
|
var init_worker_subtree = __esm({
|
|
26502
26606
|
"../../core/ts/src/worker-subtree.ts"() {
|
|
26607
|
+
"use strict";
|
|
26503
26608
|
init_worker_subtree_safe_types_generated();
|
|
26504
26609
|
WORKER_SUBTREE_CEILINGS = Object.freeze({
|
|
26505
26610
|
maxEncodedBytes: 65536,
|
|
@@ -33161,8 +33266,8 @@ function clampRule(rule, denyPrefixes, maxTTL) {
|
|
|
33161
33266
|
ttl: Math.min(rule.ttl, maxTTL)
|
|
33162
33267
|
};
|
|
33163
33268
|
}
|
|
33164
|
-
function resolveWixCachePolicy(
|
|
33165
|
-
const appRules = CACHE_OVERRIDES[
|
|
33269
|
+
function resolveWixCachePolicy(appName2) {
|
|
33270
|
+
const appRules = CACHE_OVERRIDES[appName2] ?? [];
|
|
33166
33271
|
const rules = appRules.map((r) => clampRule(r, PLATFORM_DENY_PREFIXES, PLATFORM_MAX_TTL));
|
|
33167
33272
|
return { rules, defaultCacheable: false };
|
|
33168
33273
|
}
|
|
@@ -33280,7 +33385,7 @@ function expandNavBundle(ref, ctx) {
|
|
|
33280
33385
|
};
|
|
33281
33386
|
}
|
|
33282
33387
|
function deriveNavigationConfig(app, bundleCtx) {
|
|
33283
|
-
const
|
|
33388
|
+
const appName2 = app.name;
|
|
33284
33389
|
const concrete = app.screenIds.map((screenId) => ({
|
|
33285
33390
|
screenId,
|
|
33286
33391
|
isPublic: true,
|
|
@@ -33293,7 +33398,7 @@ function deriveNavigationConfig(app, bundleCtx) {
|
|
|
33293
33398
|
const keys = (pat.match(/\{([^}]+)\}/g) ?? []).map((m) => m.slice(1, -1));
|
|
33294
33399
|
return { screenId: base, isPublic: true, paramKeys: keys, parentScreenId: "", tabId: "" };
|
|
33295
33400
|
});
|
|
33296
|
-
const ov = NAV_OVERRIDES[
|
|
33401
|
+
const ov = NAV_OVERRIDES[appName2];
|
|
33297
33402
|
if (ov?.parents) {
|
|
33298
33403
|
for (const s of [...concrete, ...templated]) {
|
|
33299
33404
|
if (ov.parents[s.screenId]) s.parentScreenId = ov.parents[s.screenId];
|
|
@@ -33304,7 +33409,7 @@ function deriveNavigationConfig(app, bundleCtx) {
|
|
|
33304
33409
|
scheme: app.urlScheme,
|
|
33305
33410
|
deepLinkPatterns: app.deepLinkPatterns ?? ov?.deepLinkPatterns ?? [],
|
|
33306
33411
|
linkableScreens,
|
|
33307
|
-
wixCachePolicy: resolveWixCachePolicy(
|
|
33412
|
+
wixCachePolicy: resolveWixCachePolicy(appName2),
|
|
33308
33413
|
// Fail-open baseline; tightened OTA via the admin app-config override. The
|
|
33309
33414
|
// DESTINATION(s) are derived generically from the app's config (no app-name
|
|
33310
33415
|
// special-casing) so the app chooses where telemetry goes via OTA:
|
|
@@ -33382,12 +33487,12 @@ function buildAppConfigDocument(req, meta, override, bundleCtx) {
|
|
|
33382
33487
|
return { config, body, etag, locale };
|
|
33383
33488
|
}
|
|
33384
33489
|
function handleAppConfigRequest(req, res, meta, override, bundleCtx) {
|
|
33385
|
-
const
|
|
33490
|
+
const appName2 = decodeURIComponent(
|
|
33386
33491
|
(req.url ?? "").replace(/^\/v1\/app-config\//, "").split("?")[0]
|
|
33387
33492
|
);
|
|
33388
|
-
if (
|
|
33493
|
+
if (appName2 !== meta.name) {
|
|
33389
33494
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
33390
|
-
res.end(JSON.stringify({ error: "unknown_app", appName }));
|
|
33495
|
+
res.end(JSON.stringify({ error: "unknown_app", appName: appName2 }));
|
|
33391
33496
|
return;
|
|
33392
33497
|
}
|
|
33393
33498
|
const { body, etag, locale } = buildAppConfigDocument(req, meta, override, bundleCtx);
|
|
@@ -36344,7 +36449,7 @@ async function handleToggleEval(req, res, state) {
|
|
|
36344
36449
|
for (const id of requested) out[id] = state.toggles[id] ?? false;
|
|
36345
36450
|
sendJson(res, 200, out);
|
|
36346
36451
|
}
|
|
36347
|
-
function evalContextFromReq(req,
|
|
36452
|
+
function evalContextFromReq(req, appName2) {
|
|
36348
36453
|
const h = (k) => {
|
|
36349
36454
|
const v = req.headers[k];
|
|
36350
36455
|
return typeof v === "string" ? v : void 0;
|
|
@@ -36352,7 +36457,7 @@ function evalContextFromReq(req, appName) {
|
|
|
36352
36457
|
return {
|
|
36353
36458
|
sessionId: h("x-himalaya-session") ?? "dev-session",
|
|
36354
36459
|
userId: h("x-himalaya-user"),
|
|
36355
|
-
appId:
|
|
36460
|
+
appId: appName2,
|
|
36356
36461
|
platform: h("x-himalaya-platform"),
|
|
36357
36462
|
appVersion: h("x-himalaya-app-version"),
|
|
36358
36463
|
locale: typeof req.headers["accept-language"] === "string" ? req.headers["accept-language"].split(",")[0] : void 0
|
|
@@ -37500,8 +37605,8 @@ async function handleActionHandlerBundleGet(res, app) {
|
|
|
37500
37605
|
}
|
|
37501
37606
|
async function serveStatic(req, res, root, prefix) {
|
|
37502
37607
|
const requested = decodeURIComponent((req.url ?? "").split("?")[0]);
|
|
37503
|
-
const
|
|
37504
|
-
const safe = normalize3(
|
|
37608
|
+
const relative13 = requested.replace(prefix, "").replace(/^\//, "");
|
|
37609
|
+
const safe = normalize3(relative13).replace(/^(\.\.[\/\\])+/, "");
|
|
37505
37610
|
const fullPath = resolve31(root, safe);
|
|
37506
37611
|
if (!fullPath.startsWith(root)) {
|
|
37507
37612
|
return send(res, 403, "forbidden");
|
|
@@ -37665,19 +37770,19 @@ function handleAssetLinks(res, state) {
|
|
|
37665
37770
|
});
|
|
37666
37771
|
}
|
|
37667
37772
|
function createDevServer(opts = {}) {
|
|
37668
|
-
const
|
|
37773
|
+
const appName2 = opts.app ?? "sample";
|
|
37669
37774
|
if (!opts.preloaded) {
|
|
37670
|
-
throw new Error(`createDevServer requires a preloaded module for "${
|
|
37775
|
+
throw new Error(`createDevServer requires a preloaded module for "${appName2}". Preload via loadApp("${appName2}").`);
|
|
37671
37776
|
}
|
|
37672
37777
|
checkRegistry(opts.preloaded.module.actions);
|
|
37673
37778
|
const port = opts.port ?? Number(process.env.HIMALAYA_DEV_PORT ?? 8080);
|
|
37674
37779
|
const hotReloadEnabled = opts.enableHotReload ?? process.env.HIMALAYA_DEV_HOT_RELOAD === "1";
|
|
37675
37780
|
const state = {
|
|
37676
|
-
appName,
|
|
37781
|
+
appName: appName2,
|
|
37677
37782
|
// Store construction is cheap now; its node:sqlite DB is opened LAZILY on first query
|
|
37678
37783
|
// (store.ts), so the serve authoring plane can boot createDevServer on a Whirlwind guest
|
|
37679
37784
|
// that has no node:sqlite — the stateless build/render path never queries the demo store.
|
|
37680
|
-
store: new Store(
|
|
37785
|
+
store: new Store(appName2),
|
|
37681
37786
|
toggles: {
|
|
37682
37787
|
pinned_notes_v2: false,
|
|
37683
37788
|
weekly_review_v1: true,
|
|
@@ -37698,7 +37803,7 @@ function createDevServer(opts = {}) {
|
|
|
37698
37803
|
localOverrides: /* @__PURE__ */ new Map(),
|
|
37699
37804
|
localOverrideHistory: /* @__PURE__ */ new Map(),
|
|
37700
37805
|
app: opts.preloaded,
|
|
37701
|
-
moduleStore: opts.preloaded ? opts.preloaded.module.createStore(
|
|
37806
|
+
moduleStore: opts.preloaded ? opts.preloaded.module.createStore(appName2) : void 0,
|
|
37702
37807
|
telemetryEvents: [],
|
|
37703
37808
|
adminUrl: process.env.HIMALAYA_ADMIN_URL,
|
|
37704
37809
|
wix: createWixGatewayState(),
|
|
@@ -38224,12 +38329,6 @@ var init_src6 = __esm({
|
|
|
38224
38329
|
}
|
|
38225
38330
|
});
|
|
38226
38331
|
|
|
38227
|
-
// ../../core/serve-storage/src/wip-pointer.ts
|
|
38228
|
-
var init_wip_pointer = __esm({
|
|
38229
|
-
"../../core/serve-storage/src/wip-pointer.ts"() {
|
|
38230
|
-
}
|
|
38231
|
-
});
|
|
38232
|
-
|
|
38233
38332
|
// ../../core/serve-storage/src/release-patch.ts
|
|
38234
38333
|
import { createHash as createHash17 } from "node:crypto";
|
|
38235
38334
|
function sha256hex(b) {
|
|
@@ -42271,7 +42370,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
42271
42370
|
...collect2?.lint ? { lint, workers } : {},
|
|
42272
42371
|
...collect2?.render ? { renders } : {},
|
|
42273
42372
|
...collect2?.descriptors ? { descriptors: baked, linkableScreenIds: [...linkable] } : {},
|
|
42274
|
-
...
|
|
42373
|
+
...typeof preloaded.meta.homeScreenId === "string" && preloaded.meta.homeScreenId ? { homeScreenId: preloaded.meta.homeScreenId } : {},
|
|
42275
42374
|
...renderTokens !== void 0 ? { tokens: renderTokens } : {},
|
|
42276
42375
|
...preloaded.meta.surfaces ? { surfaceNav: preloaded.meta.surfaces } : {},
|
|
42277
42376
|
auth: (() => {
|
|
@@ -42568,7 +42667,7 @@ h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;le
|
|
|
42568
42667
|
.sw{display:flex;gap:6px}.sw span{width:22px;height:22px;border-radius:50%;border:1px solid var(--line)}
|
|
42569
42668
|
.nav{display:flex;flex-wrap:wrap;gap:6px}.nav span{font-size:12px;padding:3px 8px;border-radius:6px;background:var(--bg);border:1px solid var(--line)}
|
|
42570
42669
|
.log{list-style:none;margin:0;padding:0}.log li{display:flex;gap:10px;padding:10px 0;border-top:1px solid var(--line)}.log li:first-child{border-top:0}
|
|
42571
|
-
.log .t{color:var(--faint);font-size:12px;min-width:64px;font-variant-numeric:tabular-nums}.log .s{font-size:11px;color:var(--muted);text-transform:capitalize}.log .imgs{display:flex;gap:6px;margin-top:6px}.log .imgs img{height:72px;border-radius:8px;border:1px solid var(--line);cursor:zoom-in}
|
|
42670
|
+
.log .t{color:var(--faint);font-size:12px;min-width:64px;font-variant-numeric:tabular-nums}.log .s{font-size:11px;color:var(--muted);text-transform:capitalize}.log .by{font-size:11px;color:var(--faint)}.log .imgs{display:flex;gap:6px;margin-top:6px}.log .imgs img{height:72px;border-radius:8px;border:1px solid var(--line);cursor:zoom-in}
|
|
42572
42671
|
.empty{color:var(--faint);font-size:13px;padding:8px 0}
|
|
42573
42672
|
#lb{position:fixed;inset:0;background:rgba(0,0,0,.72);display:none;align-items:center;justify-content:center;z-index:9;cursor:zoom-out}#lb img{max-height:92vh;max-width:92vw;border-radius:14px;background:#fff}
|
|
42574
42673
|
.enter{animation:enter .7s cubic-bezier(.2,.8,.2,1) both}@keyframes enter{from{opacity:0;transform:translateY(10px) scale(.94);filter:grayscale(1)}to{opacity:1;transform:none;filter:none}}
|
|
@@ -42697,7 +42796,7 @@ function render(s){
|
|
|
42697
42796
|
s.steps.forEach(function(name,i){var d=el("div","step"+(i+1<n?" done":i+1===n?" cur":""));d.appendChild(el("div","bar"));d.appendChild(el("div","lbl",(i+1)+". "+name));steps.appendChild(d)});
|
|
42698
42797
|
var last=s.journal[0];
|
|
42699
42798
|
$("nowmsg").textContent=last?last.message:"Waiting for the first postcard.";
|
|
42700
|
-
$("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+ago(last.ts)):"Now";
|
|
42799
|
+
$("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+(last.by?"noted by "+last.by+" \xB7 ":"")+ago(last.ts)):"Now";
|
|
42701
42800
|
var film=$("film");clear(film);
|
|
42702
42801
|
if(!rewinding){var n0=s.timelineFrames||0;$("scrub").hidden=n0<2;$("slider").max=String(Math.max(1,n0-1));$("slider").value=$("slider").max}
|
|
42703
42802
|
if(rewinding){paintStill(s)}else{$("still").hidden=true;$("focus").hidden=false;var focus=$("focus");
|
|
@@ -42729,7 +42828,7 @@ function render(s){
|
|
|
42729
42828
|
if(s.app.palette.length){var sw=el("div","sw");s.app.palette.forEach(function(c){var d=el("span");d.style.background=c.hex;d.title=c.name+" "+c.hex;sw.appendChild(d)});brand.appendChild(sw)}
|
|
42730
42829
|
var nav=$("nav");clear(nav);$("navcard").style.display=s.nav.length&&!s.map?"":"none";drawMap(s.map);s.nav.forEach(function(e){nav.appendChild(el("span",null,e.from+" \u2192 "+e.to))});
|
|
42731
42830
|
var log=$("log");clear(log);if(!s.journal.length)log.appendChild(el("li","empty","Postcards the agent journals appear here."));
|
|
42732
|
-
s.journal.forEach(function(j){var li=el("li");li.appendChild(el("div","t",hhmm(j.ts)));var body=el("div");body.appendChild(el("div",null,j.message));if(j.step)body.appendChild(el("div","s","step "+j.stepNumber+" \xB7 "+j.step));
|
|
42831
|
+
s.journal.forEach(function(j){var li=el("li");li.appendChild(el("div","t",hhmm(j.ts)));var body=el("div");body.appendChild(el("div",null,j.message));if(j.step)body.appendChild(el("div","s","step "+j.stepNumber+" \xB7 "+j.step));if(j.by)body.appendChild(el("div","by","noted by "+j.by));
|
|
42733
42832
|
if(j.images.length){var row=el("div","imgs");j.images.forEach(function(u){row.appendChild(img(u))});body.appendChild(row)}li.appendChild(body);log.appendChild(li)});
|
|
42734
42833
|
paintPop(s);
|
|
42735
42834
|
}
|
|
@@ -43502,9 +43601,10 @@ function buildView(dir, memory, now) {
|
|
|
43502
43601
|
journal: entries.slice(-MAX_JOURNAL).reverse().map((e) => ({
|
|
43503
43602
|
ts: e.ts,
|
|
43504
43603
|
message: e.message,
|
|
43505
|
-
step: e.step ?? null,
|
|
43506
|
-
stepNumber: e.stepNumber ?? null,
|
|
43507
|
-
images: (e.images ?? []).map((i) => historyUrl(basename10(i.file)))
|
|
43604
|
+
step: isCliEntry(e) ? null : e.step ?? null,
|
|
43605
|
+
stepNumber: isCliEntry(e) ? null : e.stepNumber ?? null,
|
|
43606
|
+
images: (e.images ?? []).map((i) => historyUrl(basename10(i.file))),
|
|
43607
|
+
by: isCliEntry(e) ? CLI_AUTHOR : null
|
|
43508
43608
|
})),
|
|
43509
43609
|
screens,
|
|
43510
43610
|
focus,
|
|
@@ -44752,6 +44852,109 @@ var init_notify_setup = __esm({
|
|
|
44752
44852
|
}
|
|
44753
44853
|
});
|
|
44754
44854
|
|
|
44855
|
+
// src/milestones.ts
|
|
44856
|
+
var milestones_exports = {};
|
|
44857
|
+
__export(milestones_exports, {
|
|
44858
|
+
afterDraftPush: () => afterDraftPush,
|
|
44859
|
+
afterRenderPng: () => afterRenderPng,
|
|
44860
|
+
afterTestRun: () => afterTestRun,
|
|
44861
|
+
displayPath: () => displayPath,
|
|
44862
|
+
homeScreenIdOf: () => homeScreenIdOf,
|
|
44863
|
+
openBoardForSession: () => openBoardForSession,
|
|
44864
|
+
progressCommand: () => progressCommand,
|
|
44865
|
+
sessionSteps: () => sessionSteps,
|
|
44866
|
+
testPostcardMessage: () => testPostcardMessage
|
|
44867
|
+
});
|
|
44868
|
+
import { existsSync as existsSync44, readFileSync as readFileSync48 } from "node:fs";
|
|
44869
|
+
import { basename as basename12, isAbsolute as isAbsolute4, join as join42, relative as relative8 } from "node:path";
|
|
44870
|
+
function homeScreenIdOf(dir) {
|
|
44871
|
+
let src;
|
|
44872
|
+
try {
|
|
44873
|
+
src = readFileSync48(join42(dir, "dev", "index.ts"), "utf8");
|
|
44874
|
+
} catch {
|
|
44875
|
+
return null;
|
|
44876
|
+
}
|
|
44877
|
+
const m = /^[ \t]*homeScreenId[ \t]*:[ \t]*(?:"((?:[^"\\\n]|\\.)*)"|'((?:[^'\\\n]|\\.)*)')/m.exec(src);
|
|
44878
|
+
const id = m ? m[1] ?? m[2] : void 0;
|
|
44879
|
+
return id && /^[A-Za-z0-9_.\-/{}]+$/.test(id) ? id : null;
|
|
44880
|
+
}
|
|
44881
|
+
function displayPath(p, cwd = process.cwd()) {
|
|
44882
|
+
const rel = relative8(cwd, p);
|
|
44883
|
+
return rel && !rel.startsWith("..") && !isAbsolute4(rel) ? rel : p;
|
|
44884
|
+
}
|
|
44885
|
+
function progressCommand(opts) {
|
|
44886
|
+
return `himi progress "<${opts.what}>"${opts.step ? ` --step ${opts.step}` : ""}${opts.image ? ` --image ${shellQuote(opts.image)}` : ""}${contentArg(opts.content)}`;
|
|
44887
|
+
}
|
|
44888
|
+
function sessionSteps(opts) {
|
|
44889
|
+
const content = displayPath(opts.dir, opts.cwd);
|
|
44890
|
+
const home = opts.home ?? "<homeScreenId>";
|
|
44891
|
+
const shot = `.himi/shots/${home}.png`;
|
|
44892
|
+
return [
|
|
44893
|
+
`himi run --watch${contentArg(content)} & \u2014 now, in this session: keep it running in the background. The live preview repaints on every save and serves the build board at <its url>/__himi/studio/`,
|
|
44894
|
+
`himi render ${shellQuote(home)} --png --device iphone${contentArg(content)} \u2014 the first picture, written to ${shot}${opts.home ? "" : " (the id is the dev module's homeScreenId)"}; the CLI journals it as the first look`,
|
|
44895
|
+
`${progressCommand({ what: "where the build starts", step: "plan", image: shot, content })} \u2014 your postcard for the owner, with that picture`
|
|
44896
|
+
];
|
|
44897
|
+
}
|
|
44898
|
+
async function openBoardForSession(dir, cwd = process.cwd()) {
|
|
44899
|
+
try {
|
|
44900
|
+
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
44901
|
+
const { page, url } = openStudio2(dir);
|
|
44902
|
+
const rel = relative8(cwd, page);
|
|
44903
|
+
return { page: rel && !rel.startsWith("..") && !isAbsolute4(rel) ? rel : page, url, opened: false };
|
|
44904
|
+
} catch (e) {
|
|
44905
|
+
return { opened: false, error: `the build board was not created: ${e.message} \u2014 \`himi studio --no-open\` in the app retries it` };
|
|
44906
|
+
}
|
|
44907
|
+
}
|
|
44908
|
+
function journal(dir, milestone, message, extra) {
|
|
44909
|
+
const r = journalMilestone(dir, { milestone, message, ...extra });
|
|
44910
|
+
return r.journaled ? { journaled: true, milestone, message } : void 0;
|
|
44911
|
+
}
|
|
44912
|
+
function afterRenderPng(dir, input) {
|
|
44913
|
+
const postcard = input.renderable && input.homeScreenId !== null && input.screenId === input.homeScreenId ? journal(dir, "first-look", `First look at ${appName(dir)}: the home screen, where the build starts.`, { image: input.pngFile, ...input.now ? { now: input.now } : {} }) : void 0;
|
|
44914
|
+
return {
|
|
44915
|
+
...postcard ? { postcard } : {},
|
|
44916
|
+
next: input.renderable ? [progressCommand({ what: "what changed", image: displayPath(input.pngFile), content: input.content })] : []
|
|
44917
|
+
};
|
|
44918
|
+
}
|
|
44919
|
+
function testPostcardMessage(s) {
|
|
44920
|
+
const links = s.broken === void 0 ? "" : `, ${plural(s.broken, "broken link")}`;
|
|
44921
|
+
const unreached = s.unreached ? `, ${plural(s.unreached, "screen")} nothing links to` : "";
|
|
44922
|
+
return `Test crawl: ${plural(s.screens, "screen")} and ${plural(s.actions, "action")} exercised${links}${unreached} \u2014 ${s.errors ? `${plural(s.errors, "error")} to fix` : "no errors"}.`;
|
|
44923
|
+
}
|
|
44924
|
+
function afterTestRun(dir, input) {
|
|
44925
|
+
const postcard = journal(dir, "test", testPostcardMessage(input), {
|
|
44926
|
+
ref: input.runId,
|
|
44927
|
+
...input.homeShot && existsSync44(input.homeShot) ? { image: input.homeShot } : {},
|
|
44928
|
+
...input.now ? { now: input.now } : {}
|
|
44929
|
+
});
|
|
44930
|
+
return {
|
|
44931
|
+
...postcard ? { postcard } : {},
|
|
44932
|
+
next: [
|
|
44933
|
+
input.boardOpen ? "the build board's App map now shows every screen this crawl reached, how they link, and any broken link \u2014 .himi/studio/index.html, or /__himi/studio/ under `himi run --watch`" : "`himi studio` opens the build board, whose App map draws every screen this crawl reached, how they link, and any broken link"
|
|
44934
|
+
]
|
|
44935
|
+
};
|
|
44936
|
+
}
|
|
44937
|
+
function afterDraftPush(dir, input) {
|
|
44938
|
+
const postcard = journal(dir, "draft", `Draft pushed: release ${input.releaseId.slice(0, 12)} of ${input.app} \u2014 owner-private, not live.`, {
|
|
44939
|
+
ref: input.releaseId,
|
|
44940
|
+
...input.now ? { now: input.now } : {}
|
|
44941
|
+
});
|
|
44942
|
+
return {
|
|
44943
|
+
...postcard ? { postcard } : {},
|
|
44944
|
+
next: `${progressCommand({ what: "what the owner can review in this draft", step: "review", content: input.content })} \u2014 your postcard for the draft; share the preview link in chat, never in the journal`
|
|
44945
|
+
};
|
|
44946
|
+
}
|
|
44947
|
+
var contentArg, plural, appName;
|
|
44948
|
+
var init_milestones = __esm({
|
|
44949
|
+
"src/milestones.ts"() {
|
|
44950
|
+
init_progress();
|
|
44951
|
+
init_shell_quote();
|
|
44952
|
+
contentArg = (content) => content ? ` --content ${shellQuote(content)}` : "";
|
|
44953
|
+
plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
|
|
44954
|
+
appName = (dir) => appLabel(dir) ?? basename12(dir);
|
|
44955
|
+
}
|
|
44956
|
+
});
|
|
44957
|
+
|
|
44755
44958
|
// src/site-analyze/types.ts
|
|
44756
44959
|
function isRedirectUri(value) {
|
|
44757
44960
|
return /^[a-z][a-z0-9+.-]*:\/\/\S*$/i.test(value);
|
|
@@ -45189,8 +45392,8 @@ __export(template_trim_exports, {
|
|
|
45189
45392
|
routeMatcher: () => routeMatcher,
|
|
45190
45393
|
runTemplateTrim: () => runTemplateTrim
|
|
45191
45394
|
});
|
|
45192
|
-
import { cpSync, existsSync as
|
|
45193
|
-
import { dirname as dirname25, join as
|
|
45395
|
+
import { cpSync, existsSync as existsSync45, mkdirSync as mkdirSync20, readdirSync as readdirSync24, readFileSync as readFileSync49, renameSync as renameSync5, rmSync as rmSync8, statSync as statSync10, writeFileSync as writeFileSync16 } from "node:fs";
|
|
45396
|
+
import { dirname as dirname25, join as join43 } from "node:path";
|
|
45194
45397
|
function routeMatcher(pattern) {
|
|
45195
45398
|
const detail = /^\^([A-Za-z0-9_]+)\(\?:\[_\/\]\(\.\+\)\)\?\$$/.exec(pattern);
|
|
45196
45399
|
if (detail) {
|
|
@@ -45884,20 +46087,20 @@ function homeModulesPass(app, kept, edited) {
|
|
|
45884
46087
|
return { text: patched.src, dropped: patched.droppedModules };
|
|
45885
46088
|
}
|
|
45886
46089
|
function listWorkers(dir) {
|
|
45887
|
-
const root =
|
|
45888
|
-
if (!
|
|
45889
|
-
const dirs = readdirSync24(root).filter((n) => statSync10(
|
|
46090
|
+
const root = join43(dir, "tier5-src");
|
|
46091
|
+
if (!existsSync45(root)) return { dirs: [], files: {} };
|
|
46092
|
+
const dirs = readdirSync24(root).filter((n) => statSync10(join43(root, n)).isDirectory()).sort();
|
|
45890
46093
|
const files = {};
|
|
45891
46094
|
const walk2 = (abs, rel) => {
|
|
45892
46095
|
for (const name of readdirSync24(abs)) {
|
|
45893
46096
|
if (name === "node_modules") continue;
|
|
45894
|
-
const p =
|
|
46097
|
+
const p = join43(abs, name);
|
|
45895
46098
|
const r = `${rel}/${name}`;
|
|
45896
46099
|
if (statSync10(p).isDirectory()) walk2(p, r);
|
|
45897
|
-
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] =
|
|
46100
|
+
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] = readFileSync49(p, "utf8");
|
|
45898
46101
|
}
|
|
45899
46102
|
};
|
|
45900
|
-
for (const d of dirs) walk2(
|
|
46103
|
+
for (const d of dirs) walk2(join43(root, d), `tier5-src/${d}`);
|
|
45901
46104
|
return { dirs, files };
|
|
45902
46105
|
}
|
|
45903
46106
|
function csv(v) {
|
|
@@ -45920,16 +46123,16 @@ async function runTemplateTrim(req, deps) {
|
|
|
45920
46123
|
links = req.links;
|
|
45921
46124
|
}
|
|
45922
46125
|
const dir = req.dir;
|
|
45923
|
-
const devPath =
|
|
45924
|
-
const configPath =
|
|
45925
|
-
if (!
|
|
46126
|
+
const devPath = join43(dir, "dev/index.ts");
|
|
46127
|
+
const configPath = join43(dir, "config.ts");
|
|
46128
|
+
if (!existsSync45(devPath) || !existsSync45(configPath)) {
|
|
45926
46129
|
return refuse3(new TrimRefusal(`${dir} has no dev/index.ts + config.ts \u2014 point --content at an app scaffolded with \`himi init --template\``));
|
|
45927
46130
|
}
|
|
45928
46131
|
if (isTemplateSourceTree(dir)) {
|
|
45929
46132
|
return refuse3(new TrimRefusal(`${dir} is a template source tree (its identity is still __HIMI_APP_*__ sentinels) \u2014 trim the app \`himi init --template\` scaffolds from it, not the template itself`));
|
|
45930
46133
|
}
|
|
45931
|
-
const dev =
|
|
45932
|
-
const config =
|
|
46134
|
+
const dev = readFileSync49(devPath, "utf8");
|
|
46135
|
+
const config = readFileSync49(configPath, "utf8");
|
|
45933
46136
|
const workers = listWorkers(dir);
|
|
45934
46137
|
let plan;
|
|
45935
46138
|
try {
|
|
@@ -45939,23 +46142,23 @@ async function runTemplateTrim(req, deps) {
|
|
|
45939
46142
|
throw e;
|
|
45940
46143
|
}
|
|
45941
46144
|
if (req.dryRun) return { code: 0, result: { ok: true, dryRun: true, ...plan.report, validate: null } };
|
|
45942
|
-
const hadHimi =
|
|
45943
|
-
const backupRel =
|
|
45944
|
-
const backup =
|
|
46145
|
+
const hadHimi = existsSync45(join43(dir, ".himi"));
|
|
46146
|
+
const backupRel = join43(".himi", "trim-backup", (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
|
|
46147
|
+
const backup = join43(dir, backupRel);
|
|
45945
46148
|
const originals = [[devPath, "dev/index.ts"], [configPath, "config.ts"]];
|
|
45946
46149
|
const moved = [];
|
|
45947
46150
|
const restore = () => {
|
|
45948
46151
|
for (const [path2, rel] of originals) {
|
|
45949
|
-
const original =
|
|
45950
|
-
if (!
|
|
46152
|
+
const original = readFileSync49(join43(backup, rel));
|
|
46153
|
+
if (!existsSync45(path2) || !readFileSync49(path2).equals(original)) writeFileSync16(path2, original);
|
|
45951
46154
|
}
|
|
45952
|
-
for (const name of [...moved].reverse()) renameSync5(
|
|
46155
|
+
for (const name of [...moved].reverse()) renameSync5(join43(backup, "tier5-src", name), join43(dir, "tier5-src", name));
|
|
45953
46156
|
moved.length = 0;
|
|
45954
46157
|
};
|
|
45955
46158
|
const apply = () => {
|
|
45956
46159
|
const moveDir = deps.moveDir ?? renameSync5;
|
|
45957
46160
|
for (const name of plan.removedWorkers) {
|
|
45958
|
-
moveDir(
|
|
46161
|
+
moveDir(join43(dir, "tier5-src", name), join43(backup, "tier5-src", name));
|
|
45959
46162
|
moved.push(name);
|
|
45960
46163
|
}
|
|
45961
46164
|
if (plan.dev !== dev) writeFileSync16(devPath, plan.dev);
|
|
@@ -45963,8 +46166,8 @@ async function runTemplateTrim(req, deps) {
|
|
|
45963
46166
|
};
|
|
45964
46167
|
const dropBackup = () => {
|
|
45965
46168
|
rmSync8(backup, { recursive: true, force: true });
|
|
45966
|
-
for (const d of [dirname25(backup),
|
|
45967
|
-
if (d ===
|
|
46169
|
+
for (const d of [dirname25(backup), join43(dir, ".himi")]) {
|
|
46170
|
+
if (d === join43(dir, ".himi") && hadHimi) break;
|
|
45968
46171
|
try {
|
|
45969
46172
|
if (!readdirSync24(d).length) rmSync8(d, { recursive: true });
|
|
45970
46173
|
} catch {
|
|
@@ -45990,9 +46193,9 @@ async function runTemplateTrim(req, deps) {
|
|
|
45990
46193
|
return { code: 1, result: { ok: false, error: `${error} (${message}); every file was restored`, rolledBack: true, ...base(validate4) } };
|
|
45991
46194
|
};
|
|
45992
46195
|
try {
|
|
45993
|
-
mkdirSync20(
|
|
45994
|
-
for (const [path2, rel] of originals) cpSync(path2,
|
|
45995
|
-
if (plan.removedWorkers.length) mkdirSync20(
|
|
46196
|
+
mkdirSync20(join43(backup, "dev"), { recursive: true });
|
|
46197
|
+
for (const [path2, rel] of originals) cpSync(path2, join43(backup, rel));
|
|
46198
|
+
if (plan.removedWorkers.length) mkdirSync20(join43(backup, "tier5-src"), { recursive: true });
|
|
45996
46199
|
} catch (e) {
|
|
45997
46200
|
dropBackup();
|
|
45998
46201
|
return { code: 1, result: { ok: false, error: `could not back up the app before trimming it (${e.message}); nothing was changed`, rolledBack: true, ...base() } };
|
|
@@ -46005,7 +46208,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
46005
46208
|
let failure;
|
|
46006
46209
|
let validate3;
|
|
46007
46210
|
try {
|
|
46008
|
-
const written = parseApp(
|
|
46211
|
+
const written = parseApp(readFileSync49(devPath, "utf8"), readFileSync49(configPath, "utf8"));
|
|
46009
46212
|
const leftovers = leftoverNavRefs(written.nav.value, plan.removedIds);
|
|
46010
46213
|
if (leftovers.length) failure = { error: "navigation still names screens this trim removed", leftovers };
|
|
46011
46214
|
else {
|
|
@@ -46042,7 +46245,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
46042
46245
|
else if (compared) {
|
|
46043
46246
|
failure = {
|
|
46044
46247
|
...failure,
|
|
46045
|
-
error: `himi validate --strict failed on the trimmed app \u2014 the trim introduced ${
|
|
46248
|
+
error: `himi validate --strict failed on the trimmed app \u2014 the trim introduced ${plural2(compared.introduced.length, "error")} the untrimmed app does not have: ${summarize3(compared.introduced)}`,
|
|
46046
46249
|
introducedErrors: compared.introduced,
|
|
46047
46250
|
preExistingErrors: compared.preExisting
|
|
46048
46251
|
};
|
|
@@ -46058,7 +46261,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
46058
46261
|
...base(validate3),
|
|
46059
46262
|
...preExisting.length ? {
|
|
46060
46263
|
preExistingErrors: preExisting,
|
|
46061
|
-
note: `trimmed; ${
|
|
46264
|
+
note: `trimmed; ${plural2(preExisting.length, "error")} ${preExisting.length === 1 ? "was" : "were"} already present before trim: ${summarize3(preExisting)}`
|
|
46062
46265
|
} : {}
|
|
46063
46266
|
}
|
|
46064
46267
|
};
|
|
@@ -46109,7 +46312,7 @@ function summarize3(errors) {
|
|
|
46109
46312
|
const shown2 = errors.slice(0, 5).map(one).join("; ");
|
|
46110
46313
|
return errors.length > 5 ? `${shown2}; and ${errors.length - 5} more` : shown2;
|
|
46111
46314
|
}
|
|
46112
|
-
var TrimRefusal, LIT, ATOM, QUANT, CAP, SAFE_ROUTE_PATTERN, lineOf2, isStatic, entryLabel, isNode3, asItems, NAV_SCREEN_KEYS, sorted, refuse3,
|
|
46315
|
+
var TrimRefusal, LIT, ATOM, QUANT, CAP, SAFE_ROUTE_PATTERN, lineOf2, isStatic, entryLabel, isNode3, asItems, NAV_SCREEN_KEYS, sorted, refuse3, plural2;
|
|
46113
46316
|
var init_template_trim = __esm({
|
|
46114
46317
|
"src/template-trim.ts"() {
|
|
46115
46318
|
init_validate_descriptor();
|
|
@@ -46143,7 +46346,7 @@ var init_template_trim = __esm({
|
|
|
46143
46346
|
NAV_SCREEN_KEYS = /* @__PURE__ */ new Set(["screenId", "parentScreenId", "contentScreenId", "badgeScreenId"]);
|
|
46144
46347
|
sorted = (xs) => [...new Set(xs)].sort();
|
|
46145
46348
|
refuse3 = (e) => ({ code: 2, result: { ok: false, error: e.message, ...e.detail } });
|
|
46146
|
-
|
|
46349
|
+
plural2 = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
46147
46350
|
}
|
|
46148
46351
|
});
|
|
46149
46352
|
|
|
@@ -46773,8 +46976,8 @@ __export(pack_exports, {
|
|
|
46773
46976
|
});
|
|
46774
46977
|
import { createHash as createHash22 } from "node:crypto";
|
|
46775
46978
|
import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
46776
|
-
import { existsSync as
|
|
46777
|
-
import { dirname as dirname26, join as
|
|
46979
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync21, readFileSync as readFileSync50, readdirSync as readdirSync25, rmSync as rmSync9, statSync as statSync11, writeFileSync as writeFileSync17 } from "node:fs";
|
|
46980
|
+
import { dirname as dirname26, join as join44, resolve as resolve37 } from "node:path";
|
|
46778
46981
|
function writeZip(entries) {
|
|
46779
46982
|
const sorted2 = entries.slice().sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
46780
46983
|
const total = sorted2.reduce((n, e) => n + e.bytes.length, 0);
|
|
@@ -46868,13 +47071,13 @@ function inflateEntry(buf, entry) {
|
|
|
46868
47071
|
return bytes2;
|
|
46869
47072
|
}
|
|
46870
47073
|
function readIf(path2) {
|
|
46871
|
-
return
|
|
47074
|
+
return existsSync46(path2) && statSync11(path2).isFile() ? readFileSync50(path2) : null;
|
|
46872
47075
|
}
|
|
46873
47076
|
function listDir(dir) {
|
|
46874
|
-
return
|
|
47077
|
+
return existsSync46(dir) ? readdirSync25(dir).filter((f) => statSync11(join44(dir, f)).isFile()) : [];
|
|
46875
47078
|
}
|
|
46876
47079
|
function gatherReleaseEntries(appDir2) {
|
|
46877
|
-
const manifestPath =
|
|
47080
|
+
const manifestPath = join44(appDir2, HIMI_PACKAGE_MANIFEST_PATH);
|
|
46878
47081
|
const manifestBytes = readIf(manifestPath);
|
|
46879
47082
|
if (!manifestBytes) throw new Error(`no ${HIMI_PACKAGE_MANIFEST_PATH} in ${appDir2} \u2014 build a release there first`);
|
|
46880
47083
|
const manifest = JSON.parse(manifestBytes.toString("utf8"));
|
|
@@ -46898,7 +47101,7 @@ function gatherReleaseEntries(appDir2) {
|
|
|
46898
47101
|
}
|
|
46899
47102
|
const missing = [];
|
|
46900
47103
|
for (const rel of wanted) {
|
|
46901
|
-
const bytes2 = readIf(
|
|
47104
|
+
const bytes2 = readIf(join44(appDir2, rel));
|
|
46902
47105
|
if (bytes2) entries.push({ path: rel, bytes: bytes2 });
|
|
46903
47106
|
else missing.push(rel);
|
|
46904
47107
|
}
|
|
@@ -46909,12 +47112,12 @@ function gatherReleaseEntries(appDir2) {
|
|
|
46909
47112
|
);
|
|
46910
47113
|
}
|
|
46911
47114
|
for (const name of SINGLETONS) {
|
|
46912
|
-
const bytes2 = readIf(
|
|
47115
|
+
const bytes2 = readIf(join44(appDir2, name));
|
|
46913
47116
|
if (bytes2) entries.push({ path: name, bytes: bytes2 });
|
|
46914
47117
|
}
|
|
46915
47118
|
const skipped = [];
|
|
46916
47119
|
for (const sub of ["screens", "bundles", "assets", "widgets"]) {
|
|
46917
|
-
for (const f of listDir(
|
|
47120
|
+
for (const f of listDir(join44(appDir2, sub))) {
|
|
46918
47121
|
if (!wanted.has(`${sub}/${f}`)) skipped.push(`${sub}/${f}`);
|
|
46919
47122
|
}
|
|
46920
47123
|
}
|
|
@@ -46947,18 +47150,18 @@ function buildEntries(appDir2, app, opts) {
|
|
|
46947
47150
|
return { all, header, manifest, skipped };
|
|
46948
47151
|
}
|
|
46949
47152
|
function packRelease(releaseRoot, app, out, opts = {}) {
|
|
46950
|
-
const appDir2 =
|
|
47153
|
+
const appDir2 = join44(resolve37(releaseRoot), app);
|
|
46951
47154
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
46952
47155
|
const buf = writeZip(all);
|
|
46953
|
-
const isDir2 =
|
|
46954
|
-
const outFile = isDir2 ?
|
|
47156
|
+
const isDir2 = existsSync46(out) && statSync11(out).isDirectory();
|
|
47157
|
+
const outFile = isDir2 ? join44(resolve37(out), packageFileName(app, header.releaseId)) : resolve37(out);
|
|
46955
47158
|
mkdirSync21(dirname26(outFile), { recursive: true });
|
|
46956
47159
|
writeFileSync17(outFile, buf);
|
|
46957
47160
|
return { app, releaseId: header.releaseId, header, out: outFile, bytes: buf.length, entryCount: all.length, skipped };
|
|
46958
47161
|
}
|
|
46959
47162
|
function resolvePackageDirDest(outDir, app, releaseId) {
|
|
46960
47163
|
const packagedApp = (dir) => {
|
|
46961
|
-
const bytes2 = readIf(
|
|
47164
|
+
const bytes2 = readIf(join44(dir, HIMI_PACKAGE_HEADER_PATH));
|
|
46962
47165
|
if (!bytes2) return void 0;
|
|
46963
47166
|
try {
|
|
46964
47167
|
return JSON.parse(bytes2.toString("utf8")).app;
|
|
@@ -46967,15 +47170,15 @@ function resolvePackageDirDest(outDir, app, releaseId) {
|
|
|
46967
47170
|
}
|
|
46968
47171
|
};
|
|
46969
47172
|
const replaceable = (dir) => {
|
|
46970
|
-
if (!
|
|
47173
|
+
if (!existsSync46(dir)) return true;
|
|
46971
47174
|
if (!statSync11(dir).isDirectory()) return false;
|
|
46972
47175
|
return readdirSync25(dir).length === 0 || packagedApp(dir) === app;
|
|
46973
47176
|
};
|
|
46974
|
-
if (
|
|
47177
|
+
if (existsSync46(outDir) && !statSync11(outDir).isDirectory()) {
|
|
46975
47178
|
throw new Error(`refusing to write a package tree over ${outDir} \u2014 it is a file, not a directory`);
|
|
46976
47179
|
}
|
|
46977
47180
|
if (replaceable(outDir)) return outDir;
|
|
46978
|
-
const child =
|
|
47181
|
+
const child = join44(outDir, packageDirName(app, releaseId));
|
|
46979
47182
|
if (!replaceable(child)) {
|
|
46980
47183
|
throw new Error(
|
|
46981
47184
|
`refusing to replace ${child}: it is not empty and is not a ${app} package (no ${HIMI_PACKAGE_HEADER_PATH}). Pass --out to a new or empty directory.`
|
|
@@ -46989,13 +47192,13 @@ function packReleaseToDir(releaseRoot, app, outDir, opts = {}) {
|
|
|
46989
47192
|
"a package carrying the app's source has no --format dir form: readers that predate the source entry drop it before hashing a directory and refuse the package as tampered. Pack it as a .himi archive."
|
|
46990
47193
|
);
|
|
46991
47194
|
}
|
|
46992
|
-
const appDir2 =
|
|
47195
|
+
const appDir2 = join44(resolve37(releaseRoot), app);
|
|
46993
47196
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
46994
47197
|
const dest = resolvePackageDirDest(resolve37(outDir), app, header.releaseId);
|
|
46995
47198
|
rmSync9(dest, { recursive: true, force: true });
|
|
46996
47199
|
let bytes2 = 0;
|
|
46997
47200
|
for (const entry of all) {
|
|
46998
|
-
const target =
|
|
47201
|
+
const target = join44(dest, entry.path);
|
|
46999
47202
|
mkdirSync21(dirname26(target), { recursive: true });
|
|
47000
47203
|
writeFileSync17(target, entry.bytes);
|
|
47001
47204
|
bytes2 += entry.bytes.length;
|
|
@@ -47018,21 +47221,21 @@ function openPackageBuffer(buf) {
|
|
|
47018
47221
|
return openFromEntries(readZip(buf), { requireHeader: true });
|
|
47019
47222
|
}
|
|
47020
47223
|
function openPackageFile(file) {
|
|
47021
|
-
return openPackageBuffer(
|
|
47224
|
+
return openPackageBuffer(readFileSync50(file));
|
|
47022
47225
|
}
|
|
47023
47226
|
function openPackageDir(dir) {
|
|
47024
47227
|
const root = resolve37(dir);
|
|
47025
47228
|
const entries = /* @__PURE__ */ new Map();
|
|
47026
47229
|
const walk2 = (rel) => {
|
|
47027
|
-
const abs = rel ?
|
|
47230
|
+
const abs = rel ? join44(root, rel) : root;
|
|
47028
47231
|
for (const name of readdirSync25(abs)) {
|
|
47029
47232
|
const childRel = rel ? `${rel}/${name}` : name;
|
|
47030
|
-
const childAbs =
|
|
47233
|
+
const childAbs = join44(abs, name);
|
|
47031
47234
|
if (statSync11(childAbs).isDirectory()) walk2(childRel);
|
|
47032
|
-
else if (isSafeEntryName(childRel)) entries.set(childRel,
|
|
47235
|
+
else if (isSafeEntryName(childRel)) entries.set(childRel, readFileSync50(childAbs));
|
|
47033
47236
|
}
|
|
47034
47237
|
};
|
|
47035
|
-
if (!
|
|
47238
|
+
if (!existsSync46(root)) throw new Error(`no such package directory: ${root}`);
|
|
47036
47239
|
walk2("");
|
|
47037
47240
|
const manifestBytes = entries.get(HIMI_PACKAGE_MANIFEST_PATH);
|
|
47038
47241
|
if (manifestBytes) {
|
|
@@ -47074,10 +47277,10 @@ function unpackTo(buf, dest, appFallback) {
|
|
|
47074
47277
|
if (!app) throw new Error("package declares no app id (no himi-package.json and no manifest.app)");
|
|
47075
47278
|
if (!isSafeAppId(app)) throw new Error(`package declares an unsafe app id ${JSON.stringify(app)} \u2014 refusing to unpack it`);
|
|
47076
47279
|
const root = resolve37(dest);
|
|
47077
|
-
const appDir2 =
|
|
47280
|
+
const appDir2 = join44(root, app);
|
|
47078
47281
|
rmSync9(appDir2, { recursive: true, force: true });
|
|
47079
47282
|
for (const [rel, bytes2] of entries) {
|
|
47080
|
-
const target =
|
|
47283
|
+
const target = join44(appDir2, rel);
|
|
47081
47284
|
mkdirSync21(dirname26(target), { recursive: true });
|
|
47082
47285
|
writeFileSync17(target, bytes2);
|
|
47083
47286
|
}
|
|
@@ -47113,20 +47316,20 @@ __export(app_source_exports, {
|
|
|
47113
47316
|
writeConflicts: () => writeConflicts,
|
|
47114
47317
|
zipAppSource: () => zipAppSource
|
|
47115
47318
|
});
|
|
47116
|
-
import { readdirSync as readdirSync26, lstatSync as lstatSync8, readFileSync as
|
|
47117
|
-
import { join as
|
|
47319
|
+
import { readdirSync as readdirSync26, lstatSync as lstatSync8, readFileSync as readFileSync51, mkdirSync as mkdirSync22, writeFileSync as writeFileSync18, existsSync as existsSync47, rmSync as rmSync10, rmdirSync as rmdirSync2, unlinkSync as unlinkSync3 } from "node:fs";
|
|
47320
|
+
import { join as join45, resolve as resolve38, sep as sep10 } from "node:path";
|
|
47118
47321
|
import { deflateRawSync as deflateRawSync2 } from "node:zlib";
|
|
47119
47322
|
function walkSourceTree(dir, file, skip) {
|
|
47120
47323
|
const walk2 = (relDir) => {
|
|
47121
|
-
for (const name of readdirSync26(
|
|
47122
|
-
const rel = relDir ?
|
|
47123
|
-
const st = lstatSync8(
|
|
47324
|
+
for (const name of readdirSync26(join45(dir, relDir))) {
|
|
47325
|
+
const rel = relDir ? join45(relDir, name) : name;
|
|
47326
|
+
const st = lstatSync8(join45(dir, rel));
|
|
47124
47327
|
if (st.isSymbolicLink()) {
|
|
47125
47328
|
skip(rel);
|
|
47126
47329
|
continue;
|
|
47127
47330
|
}
|
|
47128
47331
|
if (st.isDirectory()) {
|
|
47129
|
-
if (isDeniedSourceDir(name, relDir) ||
|
|
47332
|
+
if (isDeniedSourceDir(name, relDir) || existsSync47(join45(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
|
|
47130
47333
|
else walk2(rel);
|
|
47131
47334
|
continue;
|
|
47132
47335
|
}
|
|
@@ -47144,7 +47347,7 @@ function collectAppSource(dir) {
|
|
|
47144
47347
|
const skipped = [];
|
|
47145
47348
|
walkSourceTree(
|
|
47146
47349
|
dir,
|
|
47147
|
-
(archivePath, hostRel) => entries.push({ path: archivePath, bytes:
|
|
47350
|
+
(archivePath, hostRel) => entries.push({ path: archivePath, bytes: readFileSync51(join45(dir, hostRel)) }),
|
|
47148
47351
|
(hostRel) => skipped.push(hostRel)
|
|
47149
47352
|
);
|
|
47150
47353
|
entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
@@ -47198,13 +47401,13 @@ function writeAppSource(entries, destDir) {
|
|
|
47198
47401
|
const segments = entry.path.split("/");
|
|
47199
47402
|
let dir = root;
|
|
47200
47403
|
for (const segment of segments.slice(0, -1)) {
|
|
47201
|
-
dir =
|
|
47404
|
+
dir = join45(dir, segment);
|
|
47202
47405
|
const kind = pathKind(dir);
|
|
47203
47406
|
if (kind?.isSymbolicLink()) unlinkSync3(dir);
|
|
47204
47407
|
else if (kind) continue;
|
|
47205
47408
|
mkdirSync22(dir);
|
|
47206
47409
|
}
|
|
47207
|
-
const target =
|
|
47410
|
+
const target = join45(root, ...segments);
|
|
47208
47411
|
if (pathKind(target)?.isSymbolicLink()) unlinkSync3(target);
|
|
47209
47412
|
writeFileSync18(target, entry.bytes);
|
|
47210
47413
|
written.push(entry.path);
|
|
@@ -47212,7 +47415,7 @@ function writeAppSource(entries, destDir) {
|
|
|
47212
47415
|
return written;
|
|
47213
47416
|
}
|
|
47214
47417
|
function staleSourcePaths(entries, destDir) {
|
|
47215
|
-
if (!
|
|
47418
|
+
if (!existsSync47(destDir)) return [];
|
|
47216
47419
|
const archived = new Set(entries.map((e) => e.path));
|
|
47217
47420
|
const stale = [];
|
|
47218
47421
|
walkSourceTree(destDir, (archivePath) => {
|
|
@@ -47239,7 +47442,7 @@ function writeConflicts(entries, destDir) {
|
|
|
47239
47442
|
let dir = root;
|
|
47240
47443
|
let stop = false;
|
|
47241
47444
|
for (const [i, segment] of segments.slice(0, -1).entries()) {
|
|
47242
|
-
dir =
|
|
47445
|
+
dir = join45(dir, segment);
|
|
47243
47446
|
const kind2 = pathKind(dir);
|
|
47244
47447
|
if (!kind2 || kind2.isSymbolicLink()) {
|
|
47245
47448
|
stop = true;
|
|
@@ -47251,7 +47454,7 @@ function writeConflicts(entries, destDir) {
|
|
|
47251
47454
|
break;
|
|
47252
47455
|
}
|
|
47253
47456
|
if (stop) continue;
|
|
47254
|
-
const kind = pathKind(
|
|
47457
|
+
const kind = pathKind(join45(root, ...segments));
|
|
47255
47458
|
if (kind && !kind.isSymbolicLink() && kind.isDirectory()) {
|
|
47256
47459
|
say(entry.path, "is a directory here, but the release has a file at that path");
|
|
47257
47460
|
}
|
|
@@ -47261,22 +47464,22 @@ function writeConflicts(entries, destDir) {
|
|
|
47261
47464
|
function removeStaleSource(entries, destDir) {
|
|
47262
47465
|
const root = resolve38(destDir);
|
|
47263
47466
|
const removed = staleSourcePaths(entries, root);
|
|
47264
|
-
for (const rel of removed) rmSync10(
|
|
47467
|
+
for (const rel of removed) rmSync10(join45(root, ...rel.split("/")), { force: true });
|
|
47265
47468
|
const needed = /* @__PURE__ */ new Set();
|
|
47266
47469
|
for (const entry of entries) {
|
|
47267
47470
|
if (isDeniedSourcePath(entry.path)) continue;
|
|
47268
47471
|
const segments = entry.path.split("/");
|
|
47269
47472
|
for (let i = 1; i < segments.length; i++) needed.add(segments.slice(0, i).join("/"));
|
|
47270
47473
|
}
|
|
47271
|
-
if (
|
|
47474
|
+
if (existsSync47(root)) pruneEmptyDirs(root, "", needed, removed);
|
|
47272
47475
|
return removed.sort();
|
|
47273
47476
|
}
|
|
47274
47477
|
function pruneEmptyDirs(root, rel, needed, removed) {
|
|
47275
47478
|
let empty = true;
|
|
47276
|
-
for (const name of readdirSync26(rel ?
|
|
47277
|
-
const childRel = rel ?
|
|
47479
|
+
for (const name of readdirSync26(rel ? join45(root, rel) : root)) {
|
|
47480
|
+
const childRel = rel ? join45(rel, name) : name;
|
|
47278
47481
|
const posix4 = childRel.split(sep10).join("/");
|
|
47279
|
-
const kind = lstatSync8(
|
|
47482
|
+
const kind = lstatSync8(join45(root, childRel));
|
|
47280
47483
|
if (kind.isSymbolicLink() || !kind.isDirectory() || isDeniedSourceDir(name, rel)) {
|
|
47281
47484
|
empty = false;
|
|
47282
47485
|
continue;
|
|
@@ -47286,7 +47489,7 @@ function pruneEmptyDirs(root, rel, needed, removed) {
|
|
|
47286
47489
|
empty = false;
|
|
47287
47490
|
continue;
|
|
47288
47491
|
}
|
|
47289
|
-
rmdirSync2(
|
|
47492
|
+
rmdirSync2(join45(root, childRel));
|
|
47290
47493
|
removed.push(`${posix4}/`);
|
|
47291
47494
|
}
|
|
47292
47495
|
return empty;
|
|
@@ -47341,13 +47544,13 @@ __export(eject_exports, {
|
|
|
47341
47544
|
EJECTABLE: () => EJECTABLE,
|
|
47342
47545
|
ejectModule: () => ejectModule
|
|
47343
47546
|
});
|
|
47344
|
-
import { existsSync as
|
|
47345
|
-
import { dirname as dirname27, join as
|
|
47547
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync23, readFileSync as readFileSync52, writeFileSync as writeFileSync19 } from "node:fs";
|
|
47548
|
+
import { dirname as dirname27, join as join46, relative as relative9, resolve as resolve39, sep as sep11 } from "node:path";
|
|
47346
47549
|
function locate(repoRootOrCwd, mod) {
|
|
47347
47550
|
const inRepo = resolve39(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
|
|
47348
|
-
if (
|
|
47551
|
+
if (existsSync48(inRepo)) return { path: inRepo, form: "source" };
|
|
47349
47552
|
const dist = resolve39(repoRootOrCwd, `node_modules/@wix/himalaya/dist/${mod}.mjs`);
|
|
47350
|
-
if (
|
|
47553
|
+
if (existsSync48(dist)) return { path: dist, form: "bundle" };
|
|
47351
47554
|
return null;
|
|
47352
47555
|
}
|
|
47353
47556
|
function specifiersFor(mod) {
|
|
@@ -47371,7 +47574,7 @@ function ejectModule(opts) {
|
|
|
47371
47574
|
};
|
|
47372
47575
|
}
|
|
47373
47576
|
const ext = found.form === "source" ? "ts" : "mjs";
|
|
47374
|
-
const target =
|
|
47577
|
+
const target = join46(contentDir2, "tier5-src", "_ejected", `${mod}.${ext}`);
|
|
47375
47578
|
mkdirSync23(dirname27(target), { recursive: true });
|
|
47376
47579
|
const banner = `// EJECTED from @wix/himalaya/${mod}. This app owns this file now.
|
|
47377
47580
|
//
|
|
@@ -47385,17 +47588,17 @@ function ejectModule(opts) {
|
|
|
47385
47588
|
// gate still applies. Ejecting buys layout and flow, never the floor.
|
|
47386
47589
|
|
|
47387
47590
|
`;
|
|
47388
|
-
const normalized =
|
|
47591
|
+
const normalized = readFileSync52(found.path, "utf8").replace(
|
|
47389
47592
|
/(["'])@himalaya\/([a-z0-9-]+(?:\/[a-z0-9-]+)?)\1/g,
|
|
47390
47593
|
(_m, q, sub) => `${q}@wix/himalaya/${sub}${q}`
|
|
47391
47594
|
);
|
|
47392
47595
|
writeFileSync19(target, banner + normalized);
|
|
47393
47596
|
const rewired = [];
|
|
47394
47597
|
for (const f of files) {
|
|
47395
|
-
if (!
|
|
47396
|
-
const before =
|
|
47598
|
+
if (!existsSync48(f)) continue;
|
|
47599
|
+
const before = readFileSync52(f, "utf8");
|
|
47397
47600
|
let after = before;
|
|
47398
|
-
let rel =
|
|
47601
|
+
let rel = relative9(dirname27(f), target).split(sep11).join("/").replace(/\.tsx?$/, ".js");
|
|
47399
47602
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
47400
47603
|
for (const spec of specifiersFor(mod)) {
|
|
47401
47604
|
const q = spec.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -47513,8 +47716,8 @@ var init_app_map = __esm({
|
|
|
47513
47716
|
});
|
|
47514
47717
|
|
|
47515
47718
|
// src/wix-writes.ts
|
|
47516
|
-
import { existsSync as
|
|
47517
|
-
import { join as
|
|
47719
|
+
import { existsSync as existsSync49, readFileSync as readFileSync53 } from "node:fs";
|
|
47720
|
+
import { join as join47 } from "node:path";
|
|
47518
47721
|
function isProvenRead(method, path2) {
|
|
47519
47722
|
if (/[#\x00-\x1F\x7F]/.test(path2)) return false;
|
|
47520
47723
|
const verb = method.toUpperCase();
|
|
@@ -47595,11 +47798,11 @@ function parseDataAccess(text5, from) {
|
|
|
47595
47798
|
}
|
|
47596
47799
|
function readDataAccess(dir) {
|
|
47597
47800
|
for (const name of ["SPEC.md", "MOBILE-UX.md"]) {
|
|
47598
|
-
const p =
|
|
47599
|
-
if (!
|
|
47801
|
+
const p = join47(dir, name);
|
|
47802
|
+
if (!existsSync49(p)) continue;
|
|
47600
47803
|
let text5;
|
|
47601
47804
|
try {
|
|
47602
|
-
text5 =
|
|
47805
|
+
text5 = readFileSync53(p, "utf8");
|
|
47603
47806
|
} catch {
|
|
47604
47807
|
continue;
|
|
47605
47808
|
}
|
|
@@ -47706,14 +47909,14 @@ __export(test_exports, {
|
|
|
47706
47909
|
scopeDescriptors: () => scopeDescriptors,
|
|
47707
47910
|
writeRecordedMocks: () => writeRecordedMocks
|
|
47708
47911
|
});
|
|
47709
|
-
import { existsSync as
|
|
47710
|
-
import { join as
|
|
47912
|
+
import { existsSync as existsSync50, mkdirSync as mkdirSync24, readFileSync as readFileSync54, writeFileSync as writeFileSync20 } from "node:fs";
|
|
47913
|
+
import { join as join48, resolve as resolve40 } from "node:path";
|
|
47711
47914
|
function readTestConfig(dir) {
|
|
47712
47915
|
const p = resolve40(dir, TEST_CONFIG_FILE);
|
|
47713
|
-
if (!
|
|
47916
|
+
if (!existsSync50(p)) return {};
|
|
47714
47917
|
let parsed;
|
|
47715
47918
|
try {
|
|
47716
|
-
parsed = JSON.parse(
|
|
47919
|
+
parsed = JSON.parse(readFileSync54(p, "utf8"));
|
|
47717
47920
|
} catch (e) {
|
|
47718
47921
|
throw new Error(`${TEST_CONFIG_FILE} is not valid JSON \u2014 ${e.message}`);
|
|
47719
47922
|
}
|
|
@@ -47760,7 +47963,7 @@ function readTestConfig(dir) {
|
|
|
47760
47963
|
function readNetRules(path2) {
|
|
47761
47964
|
let parsed;
|
|
47762
47965
|
try {
|
|
47763
|
-
parsed = JSON.parse(
|
|
47966
|
+
parsed = JSON.parse(readFileSync54(path2, "utf8"));
|
|
47764
47967
|
} catch (e) {
|
|
47765
47968
|
throw new Error(`--net ${path2} could not be read as JSON \u2014 ${e.message}`);
|
|
47766
47969
|
}
|
|
@@ -47781,7 +47984,7 @@ function readNetRules(path2) {
|
|
|
47781
47984
|
function defaultNetRules(dir) {
|
|
47782
47985
|
for (const rel of ["dev/net-mocks.json", "tests/net-mocks.json"]) {
|
|
47783
47986
|
const p = resolve40(dir, rel);
|
|
47784
|
-
if (
|
|
47987
|
+
if (existsSync50(p)) {
|
|
47785
47988
|
const rules = readNetRules(p);
|
|
47786
47989
|
if (rules.length) return { rules, from: rel };
|
|
47787
47990
|
}
|
|
@@ -47797,7 +48000,7 @@ function readCannedResponses() {
|
|
|
47797
48000
|
];
|
|
47798
48001
|
for (const url of candidates) {
|
|
47799
48002
|
try {
|
|
47800
|
-
const parsed = JSON.parse(
|
|
48003
|
+
const parsed = JSON.parse(readFileSync54(url, "utf8"));
|
|
47801
48004
|
const byKey = {};
|
|
47802
48005
|
for (const [k, v] of Object.entries(parsed)) {
|
|
47803
48006
|
if (!k.startsWith("//")) byKey[k] = v;
|
|
@@ -47887,8 +48090,8 @@ function writeRecordedMocks(opts) {
|
|
|
47887
48090
|
mkdir: (p) => mkdirSync24(p, { recursive: true }),
|
|
47888
48091
|
write: (p, s) => writeFileSync20(p, s)
|
|
47889
48092
|
};
|
|
47890
|
-
fs.mkdir(
|
|
47891
|
-
fs.write(
|
|
48093
|
+
fs.mkdir(join48(opts.dir, "dev"));
|
|
48094
|
+
fs.write(join48(opts.dir, "dev", "net-mocks.json"), JSON.stringify(opts.mocks, null, 2) + "\n");
|
|
47892
48095
|
return { ok: true, rules, to: "dev/net-mocks.json" };
|
|
47893
48096
|
}
|
|
47894
48097
|
function scopeDescriptors(descriptors, requestedIds, invalidScreens) {
|
|
@@ -48391,14 +48594,14 @@ var mobile_ux_lint_exports = {};
|
|
|
48391
48594
|
__export(mobile_ux_lint_exports, {
|
|
48392
48595
|
mobileUxIssues: () => mobileUxIssues
|
|
48393
48596
|
});
|
|
48394
|
-
import { existsSync as
|
|
48395
|
-
import { join as
|
|
48597
|
+
import { existsSync as existsSync51, readFileSync as readFileSync55 } from "node:fs";
|
|
48598
|
+
import { join as join49 } from "node:path";
|
|
48396
48599
|
function mobileUxIssues(dir, strict) {
|
|
48397
|
-
const file =
|
|
48398
|
-
if (!
|
|
48600
|
+
const file = join49(dir, "MOBILE-UX.md");
|
|
48601
|
+
if (!existsSync51(file)) return [];
|
|
48399
48602
|
let text5;
|
|
48400
48603
|
try {
|
|
48401
|
-
text5 =
|
|
48604
|
+
text5 = readFileSync55(file, "utf8");
|
|
48402
48605
|
} catch {
|
|
48403
48606
|
return [];
|
|
48404
48607
|
}
|
|
@@ -50073,8 +50276,8 @@ __export(functions_exports, {
|
|
|
50073
50276
|
resolveFunctionsTarget: () => resolveFunctionsTarget,
|
|
50074
50277
|
runRemoteFunctionOperation: () => runRemoteFunctionOperation
|
|
50075
50278
|
});
|
|
50076
|
-
import { readFileSync as
|
|
50077
|
-
import { join as
|
|
50279
|
+
import { readFileSync as readFileSync56, existsSync as existsSync52 } from "node:fs";
|
|
50280
|
+
import { join as join50, resolve as resolve41 } from "node:path";
|
|
50078
50281
|
function resolveFunctionsTarget(input) {
|
|
50079
50282
|
const explicitUrl = input.functionsUrl?.trim();
|
|
50080
50283
|
if (explicitUrl) return { mode: "remote", baseUrl: explicitUrl };
|
|
@@ -50093,9 +50296,9 @@ async function loadFunctionsApp(dir) {
|
|
|
50093
50296
|
}
|
|
50094
50297
|
const sources = {};
|
|
50095
50298
|
for (const definition of config.functions.functions) {
|
|
50096
|
-
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) =>
|
|
50299
|
+
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join50(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync52);
|
|
50097
50300
|
if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
|
|
50098
|
-
sources[definition.name] =
|
|
50301
|
+
sources[definition.name] = readFileSync56(source, "utf8");
|
|
50099
50302
|
}
|
|
50100
50303
|
const data = config.cms || config.data ? mergeDataResources(config) : void 0;
|
|
50101
50304
|
const dataErrors = validateDataResources(data, loaded.name).filter((issue2) => issue2.severity === "error");
|
|
@@ -50255,10 +50458,10 @@ __export(studio_reel_exports, {
|
|
|
50255
50458
|
utcDay: () => utcDay
|
|
50256
50459
|
});
|
|
50257
50460
|
import { createHash as createHash25 } from "node:crypto";
|
|
50258
|
-
import { lstatSync as lstatSync9, readFileSync as
|
|
50259
|
-
import { basename as
|
|
50461
|
+
import { lstatSync as lstatSync9, readFileSync as readFileSync57 } from "node:fs";
|
|
50462
|
+
import { basename as basename13, join as join51 } from "node:path";
|
|
50260
50463
|
function loadMemory2(dir) {
|
|
50261
|
-
const m = readJson5(
|
|
50464
|
+
const m = readJson5(join51(dir, ".himi", "studio", "memory.json"));
|
|
50262
50465
|
if (!isObj2(m) || m.version !== 1 || !isObj2(m.shots) || !Array.isArray(m.timeline)) return null;
|
|
50263
50466
|
const shots = [];
|
|
50264
50467
|
for (const [id, s] of Object.entries(m.shots)) {
|
|
@@ -50295,8 +50498,8 @@ function planReel(dir) {
|
|
|
50295
50498
|
const memory = loadMemory2(dir);
|
|
50296
50499
|
const { entries } = readProgress(dir);
|
|
50297
50500
|
const summary = summarizeProgress(entries);
|
|
50298
|
-
const manifest = readJson5(
|
|
50299
|
-
const tokens = readJson5(
|
|
50501
|
+
const manifest = readJson5(join51(dir, "himalaya.content.json"));
|
|
50502
|
+
const tokens = readJson5(join51(dir, "tokens.json"));
|
|
50300
50503
|
const accentToken = tokens?.colors?.accentPrimary;
|
|
50301
50504
|
const accentRaw = typeof accentToken === "string" ? accentToken : accentToken?.light;
|
|
50302
50505
|
const accent = typeof accentRaw === "string" && ACCENT.test(accentRaw) ? accentRaw : DEFAULT_ACCENT;
|
|
@@ -50310,14 +50513,15 @@ function planReel(dir) {
|
|
|
50310
50513
|
const postcards = entries.map((e) => ({
|
|
50311
50514
|
ts: e.ts,
|
|
50312
50515
|
message: e.message,
|
|
50313
|
-
step: str(e.step),
|
|
50314
|
-
|
|
50516
|
+
step: isCliEntry(e) ? null : str(e.step),
|
|
50517
|
+
by: isCliEntry(e) ? CLI_AUTHOR : null,
|
|
50518
|
+
files: (Array.isArray(e.images) ? e.images : []).map((i) => isObj2(i) && typeof i.file === "string" ? basename13(i.file) : "").filter((f) => HISTORY_NAME.test(f))
|
|
50315
50519
|
}));
|
|
50316
50520
|
const times = [summary.startedAt, ...timeline.map((t) => t.ts), memory?.createdAt].filter((x) => !!x).sort();
|
|
50317
50521
|
const startedAt = times[0] ?? null;
|
|
50318
50522
|
const endedAt = [summary.lastAt, ...timeline.map((t) => t.ts)].filter((x) => !!x).sort().pop() ?? null;
|
|
50319
50523
|
return {
|
|
50320
|
-
app: typeof manifest?.name === "string" && manifest.name ? manifest.name :
|
|
50524
|
+
app: typeof manifest?.name === "string" && manifest.name ? manifest.name : basename13(dir),
|
|
50321
50525
|
accent,
|
|
50322
50526
|
startedAt,
|
|
50323
50527
|
endedAt,
|
|
@@ -50338,10 +50542,10 @@ function inlineImages(dir, plan, budget = REEL_BUDGET_BYTES) {
|
|
|
50338
50542
|
const verified = (f) => {
|
|
50339
50543
|
if (!HISTORY_NAME.test(f)) return null;
|
|
50340
50544
|
try {
|
|
50341
|
-
const path2 =
|
|
50545
|
+
const path2 = join51(dir, HISTORY_DIR, f);
|
|
50342
50546
|
const st = lstatSync9(path2);
|
|
50343
50547
|
if (!st.isFile() || st.nlink !== 1) return null;
|
|
50344
|
-
const bytes2 =
|
|
50548
|
+
const bytes2 = readFileSync57(path2);
|
|
50345
50549
|
return createHash25("sha256").update(bytes2).digest("hex") === f.slice(0, 64) && imageExtension(bytes2) === f.slice(65) ? bytes2 : null;
|
|
50346
50550
|
} catch {
|
|
50347
50551
|
return null;
|
|
@@ -50435,7 +50639,7 @@ function renderReel(plan, images) {
|
|
|
50435
50639
|
.flipcap{flex:1;min-width:220px}.flipcap .t{font-size:40px;font-weight:700;font-variant-numeric:tabular-nums;color:var(--accent)}.bar{height:4px;background:var(--line);border-radius:2px;margin-top:16px}.bar div{height:4px;background:var(--accent);border-radius:2px;width:0}
|
|
50436
50640
|
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:18px}.grid figure{margin:0;text-align:center}.grid img{width:100%;aspect-ratio:390/844;object-fit:cover;object-position:top;border:6px solid #111;border-radius:22px;background:#fff}
|
|
50437
50641
|
figcaption{font-size:12px;color:var(--muted);margin-top:6px;word-break:break-all}
|
|
50438
|
-
.log{list-style:none;padding:0;margin:0}.log li{display:flex;gap:14px;padding:12px 0;border-top:1px solid var(--line)}.log .t{min-width:52px;color:var(--muted);font-variant-numeric:tabular-nums}.log .s{font-size:12px;color:var(--muted);text-transform:capitalize}
|
|
50642
|
+
.log{list-style:none;padding:0;margin:0}.log li{display:flex;gap:14px;padding:12px 0;border-top:1px solid var(--line)}.log .t{min-width:52px;color:var(--muted);font-variant-numeric:tabular-nums}.log .s{font-size:12px;color:var(--muted);text-transform:capitalize}.log .by{font-size:12px;color:var(--muted)}
|
|
50439
50643
|
.log .imgs{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap}.log .imgs img{height:120px;border-radius:10px;border:1px solid var(--line)}
|
|
50440
50644
|
footer{margin-top:48px;font-size:12px;color:var(--muted)}
|
|
50441
50645
|
</style></head><body><div class="wrap">
|
|
@@ -50446,7 +50650,7 @@ ${flip}
|
|
|
50446
50650
|
<h2>Where it ended up</h2>
|
|
50447
50651
|
<div class="grid">${plan.finals.map((f) => `<figure>${img(f.file, f.id)}<figcaption>${escapeHtml(f.id)}</figcaption></figure>`).join("")}</div>
|
|
50448
50652
|
<h2>Postcards</h2>
|
|
50449
|
-
<ul class="log">${plan.postcards.map((c) => `<li><div class="t">${clock(c.ts)}</div><div><div>${escapeHtml(c.message)}</div>${c.step ? `<div class="s">step ${JOURNEY_STEPS.indexOf(c.step) + 1} \xB7 ${escapeHtml(c.step)}</div>` : ""}${c.files.length ? `<div class="imgs">${c.files.map((f) => img(f, c.message)).join("")}</div>` : ""}</div></li>`).join("") || `<li class="muted">No postcards were journaled.</li>`}</ul>
|
|
50653
|
+
<ul class="log">${plan.postcards.map((c) => `<li><div class="t">${clock(c.ts)}</div><div><div>${escapeHtml(c.message)}</div>${c.step ? `<div class="s">step ${JOURNEY_STEPS.indexOf(c.step) + 1} \xB7 ${escapeHtml(c.step)}</div>` : ""}${c.by ? `<div class="by">noted by ${escapeHtml(c.by)}</div>` : ""}${c.files.length ? `<div class="imgs">${c.files.map((f) => img(f, c.message)).join("")}</div>` : ""}</div></li>`).join("") || `<li class="muted">No postcards were journaled.</li>`}</ul>
|
|
50450
50654
|
<footer>Built with himi.${plan.dropped ? ` ${count2(plan.dropped)} pictures were left out to keep this file small.` : ""}</footer>
|
|
50451
50655
|
</div>
|
|
50452
50656
|
<script>
|
|
@@ -50475,7 +50679,7 @@ var init_studio_reel = __esm({
|
|
|
50475
50679
|
mimeOf = (file) => MIME2[file.slice(65)] ?? "image/png";
|
|
50476
50680
|
readJson5 = (file) => {
|
|
50477
50681
|
try {
|
|
50478
|
-
return JSON.parse(
|
|
50682
|
+
return JSON.parse(readFileSync57(file, "utf8"));
|
|
50479
50683
|
} catch {
|
|
50480
50684
|
return null;
|
|
50481
50685
|
}
|
|
@@ -50506,9 +50710,9 @@ __export(native_decode_exports, {
|
|
|
50506
50710
|
runNativeDecode: () => runNativeDecode
|
|
50507
50711
|
});
|
|
50508
50712
|
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
50509
|
-
import { existsSync as
|
|
50713
|
+
import { existsSync as existsSync53, mkdtempSync as mkdtempSync2, readFileSync as readFileSync58, rmSync as rmSync11, writeFileSync as writeFileSync21 } from "node:fs";
|
|
50510
50714
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
50511
|
-
import { join as
|
|
50715
|
+
import { join as join52 } from "node:path";
|
|
50512
50716
|
import { fileURLToPath as fileURLToPath20 } from "node:url";
|
|
50513
50717
|
function nativeDecodePackageDir() {
|
|
50514
50718
|
return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
|
|
@@ -50518,8 +50722,8 @@ function nativeDecodeAndroidHarnessDir() {
|
|
|
50518
50722
|
}
|
|
50519
50723
|
function nativeOracleShipped() {
|
|
50520
50724
|
return {
|
|
50521
|
-
ios:
|
|
50522
|
-
android:
|
|
50725
|
+
ios: existsSync53(join52(nativeDecodePackageDir(), "Package.swift")),
|
|
50726
|
+
android: existsSync53(join52(nativeDecodeAndroidHarnessDir(), "gradlew"))
|
|
50523
50727
|
};
|
|
50524
50728
|
}
|
|
50525
50729
|
function detectNativeDecode(options = {}) {
|
|
@@ -50530,7 +50734,7 @@ function detectNativeDecode(options = {}) {
|
|
|
50530
50734
|
return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
|
|
50531
50735
|
}
|
|
50532
50736
|
if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
|
|
50533
|
-
const packageAvailable = options.packageAvailable ??
|
|
50737
|
+
const packageAvailable = options.packageAvailable ?? existsSync53(join52(packageDir, "Package.swift"));
|
|
50534
50738
|
if (!packageAvailable) {
|
|
50535
50739
|
return {
|
|
50536
50740
|
platform: "ios",
|
|
@@ -50542,7 +50746,7 @@ function detectNativeDecode(options = {}) {
|
|
|
50542
50746
|
}
|
|
50543
50747
|
function localPropertiesSdk(harnessDir) {
|
|
50544
50748
|
try {
|
|
50545
|
-
const match =
|
|
50749
|
+
const match = readFileSync58(join52(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
|
|
50546
50750
|
return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
|
|
50547
50751
|
} catch {
|
|
50548
50752
|
return null;
|
|
@@ -50550,8 +50754,8 @@ function localPropertiesSdk(harnessDir) {
|
|
|
50550
50754
|
}
|
|
50551
50755
|
function detectAndroidNativeDecode(options = {}) {
|
|
50552
50756
|
const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
|
|
50553
|
-
const gradlew =
|
|
50554
|
-
const gradlewAvailable = options.gradlewAvailable ??
|
|
50757
|
+
const gradlew = join52(harnessDir, "gradlew");
|
|
50758
|
+
const gradlewAvailable = options.gradlewAvailable ?? existsSync53(gradlew);
|
|
50555
50759
|
if (!gradlewAvailable) {
|
|
50556
50760
|
return {
|
|
50557
50761
|
platform: "android",
|
|
@@ -50561,7 +50765,7 @@ function detectAndroidNativeDecode(options = {}) {
|
|
|
50561
50765
|
}
|
|
50562
50766
|
const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
|
|
50563
50767
|
const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
|
|
50564
|
-
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 &&
|
|
50768
|
+
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync53(sdk));
|
|
50565
50769
|
if (!sdkAvailable) {
|
|
50566
50770
|
return {
|
|
50567
50771
|
platform: "android",
|
|
@@ -50633,14 +50837,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
|
|
|
50633
50837
|
return verdicts;
|
|
50634
50838
|
}
|
|
50635
50839
|
function runNativeDecode(options) {
|
|
50636
|
-
const descriptorDir = mkdtempSync2(
|
|
50840
|
+
const descriptorDir = mkdtempSync2(join52(tmpdir3(), "himi-native-decode-"));
|
|
50637
50841
|
const startedAt = Date.now();
|
|
50638
50842
|
try {
|
|
50639
50843
|
for (const descriptor of options.descriptors) {
|
|
50640
50844
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
50641
50845
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
50642
50846
|
}
|
|
50643
|
-
writeFileSync21(
|
|
50847
|
+
writeFileSync21(join52(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
50644
50848
|
}
|
|
50645
50849
|
options.progress?.("building cached Swift oracle");
|
|
50646
50850
|
execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
|
|
@@ -50652,7 +50856,7 @@ function runNativeDecode(options) {
|
|
|
50652
50856
|
encoding: "utf8"
|
|
50653
50857
|
}).trim();
|
|
50654
50858
|
options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
50655
|
-
const stdout = execFileSync5(
|
|
50859
|
+
const stdout = execFileSync5(join52(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
|
|
50656
50860
|
stdio: ["ignore", "pipe", "pipe"],
|
|
50657
50861
|
encoding: "utf8"
|
|
50658
50862
|
});
|
|
@@ -50670,15 +50874,15 @@ function runNativeDecode(options) {
|
|
|
50670
50874
|
}
|
|
50671
50875
|
}
|
|
50672
50876
|
function runAndroidNativeDecode(options) {
|
|
50673
|
-
const descriptorDir = mkdtempSync2(
|
|
50674
|
-
const outputPath =
|
|
50877
|
+
const descriptorDir = mkdtempSync2(join52(tmpdir3(), "himi-native-decode-android-"));
|
|
50878
|
+
const outputPath = join52(descriptorDir, "verdicts.ndjson");
|
|
50675
50879
|
const startedAt = Date.now();
|
|
50676
50880
|
try {
|
|
50677
50881
|
for (const descriptor of options.descriptors) {
|
|
50678
50882
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
50679
50883
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
50680
50884
|
}
|
|
50681
|
-
writeFileSync21(
|
|
50885
|
+
writeFileSync21(join52(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
50682
50886
|
}
|
|
50683
50887
|
options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
50684
50888
|
execFileSync5(options.gradlew, [
|
|
@@ -50693,7 +50897,7 @@ function runAndroidNativeDecode(options) {
|
|
|
50693
50897
|
stdio: ["ignore", "ignore", "pipe"],
|
|
50694
50898
|
encoding: "utf8"
|
|
50695
50899
|
});
|
|
50696
|
-
const stdout =
|
|
50900
|
+
const stdout = readFileSync58(outputPath, "utf8");
|
|
50697
50901
|
return {
|
|
50698
50902
|
platform: "android",
|
|
50699
50903
|
verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
|
|
@@ -50763,13 +50967,13 @@ __export(browser_authoring_exports, {
|
|
|
50763
50967
|
});
|
|
50764
50968
|
import { createServer as createServer3 } from "node:http";
|
|
50765
50969
|
import { createHash as createHash26, randomBytes as randomBytes4 } from "node:crypto";
|
|
50766
|
-
import { existsSync as
|
|
50767
|
-
import { join as
|
|
50970
|
+
import { existsSync as existsSync54, readdirSync as readdirSync27, readFileSync as readFileSync59, realpathSync as realpathSync6, statSync as statSync12 } from "node:fs";
|
|
50971
|
+
import { join as join53, posix as posix2, relative as relative10, sep as sep12 } from "node:path";
|
|
50768
50972
|
function humanMs(ms) {
|
|
50769
50973
|
return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
|
|
50770
50974
|
}
|
|
50771
50975
|
function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
50772
|
-
const root =
|
|
50976
|
+
const root = join53(tier5SrcDir, bundleName);
|
|
50773
50977
|
const files = {};
|
|
50774
50978
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
50775
50979
|
const walk2 = (abs, rel) => {
|
|
@@ -50777,16 +50981,16 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
|
50777
50981
|
if (visitedDirs.has(real)) return;
|
|
50778
50982
|
visitedDirs.add(real);
|
|
50779
50983
|
for (const name of readdirSync27(abs).sort()) {
|
|
50780
|
-
const childAbs =
|
|
50984
|
+
const childAbs = join53(abs, name);
|
|
50781
50985
|
const childRel = posix2.join(rel, name);
|
|
50782
50986
|
if (statSync12(childAbs).isDirectory()) {
|
|
50783
50987
|
walk2(childAbs, childRel);
|
|
50784
50988
|
} else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
|
|
50785
|
-
files[childRel] =
|
|
50989
|
+
files[childRel] = readFileSync59(childAbs, "utf8");
|
|
50786
50990
|
}
|
|
50787
50991
|
}
|
|
50788
50992
|
};
|
|
50789
|
-
if (!
|
|
50993
|
+
if (!existsSync54(root)) return null;
|
|
50790
50994
|
walk2(root, `/tier5-src/${bundleName}`);
|
|
50791
50995
|
const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
|
|
50792
50996
|
if (!entry) return null;
|
|
@@ -50803,20 +51007,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
|
|
|
50803
51007
|
const spec = m[1];
|
|
50804
51008
|
const virtual = posix2.normalize(posix2.join(dir, spec));
|
|
50805
51009
|
if (!virtual.startsWith("/tier5-src/")) continue;
|
|
50806
|
-
const onDisk =
|
|
51010
|
+
const onDisk = join53(tier5SrcDir, virtual.slice("/tier5-src/".length));
|
|
50807
51011
|
const candidates = [
|
|
50808
51012
|
onDisk,
|
|
50809
51013
|
`${onDisk}.ts`,
|
|
50810
51014
|
`${onDisk}.js`,
|
|
50811
51015
|
onDisk.replace(/\.js$/, ".ts"),
|
|
50812
|
-
|
|
50813
|
-
|
|
51016
|
+
join53(onDisk, "index.ts"),
|
|
51017
|
+
join53(onDisk, "index.js")
|
|
50814
51018
|
];
|
|
50815
51019
|
for (const abs of candidates) {
|
|
50816
|
-
if (!
|
|
50817
|
-
const key2 = `/tier5-src/${
|
|
51020
|
+
if (!existsSync54(abs) || statSync12(abs).isDirectory()) continue;
|
|
51021
|
+
const key2 = `/tier5-src/${relative10(tier5SrcDir, abs).split(sep12).join(posix2.sep)}`;
|
|
50818
51022
|
if (key2 in files) break;
|
|
50819
|
-
files[key2] =
|
|
51023
|
+
files[key2] = readFileSync59(abs, "utf8");
|
|
50820
51024
|
queue.push(key2);
|
|
50821
51025
|
break;
|
|
50822
51026
|
}
|
|
@@ -50851,7 +51055,7 @@ function collectSdkModules(files, resolveSubpath) {
|
|
|
50851
51055
|
function sdkSubpathReader(resolve48) {
|
|
50852
51056
|
return (sub) => {
|
|
50853
51057
|
try {
|
|
50854
|
-
return
|
|
51058
|
+
return readFileSync59(resolve48(`@wix/himalaya/${sub}`), "utf8");
|
|
50855
51059
|
} catch {
|
|
50856
51060
|
return null;
|
|
50857
51061
|
}
|
|
@@ -51023,8 +51227,8 @@ __export(coverage_exports, {
|
|
|
51023
51227
|
suppressedNativeKeys: () => suppressedNativeKeys,
|
|
51024
51228
|
trendAndStore: () => trendAndStore
|
|
51025
51229
|
});
|
|
51026
|
-
import { existsSync as
|
|
51027
|
-
import { dirname as dirname28, join as
|
|
51230
|
+
import { existsSync as existsSync55, mkdirSync as mkdirSync25, readFileSync as readFileSync60, writeFileSync as writeFileSync22 } from "node:fs";
|
|
51231
|
+
import { dirname as dirname28, join as join54 } from "node:path";
|
|
51028
51232
|
function suppressedNativeKeys(oracle) {
|
|
51029
51233
|
return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
|
|
51030
51234
|
}
|
|
@@ -51204,11 +51408,11 @@ function assembleLedger(r, options = {}) {
|
|
|
51204
51408
|
return out;
|
|
51205
51409
|
}
|
|
51206
51410
|
function trendAndStore(dir, entries, suppressed) {
|
|
51207
|
-
const p =
|
|
51411
|
+
const p = join54(dir, LEDGER_FILE);
|
|
51208
51412
|
let previous = null;
|
|
51209
51413
|
try {
|
|
51210
|
-
if (
|
|
51211
|
-
const parsed = JSON.parse(
|
|
51414
|
+
if (existsSync55(p)) {
|
|
51415
|
+
const parsed = JSON.parse(readFileSync60(p, "utf8"));
|
|
51212
51416
|
if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
|
|
51213
51417
|
}
|
|
51214
51418
|
} catch {
|
|
@@ -51247,11 +51451,11 @@ function formatLedger(entries, trend) {
|
|
|
51247
51451
|
return out.join("\n");
|
|
51248
51452
|
}
|
|
51249
51453
|
function diffAndStoreObservations(dir, current) {
|
|
51250
|
-
const p =
|
|
51454
|
+
const p = join54(dir, OBS_FILE);
|
|
51251
51455
|
let previous = null;
|
|
51252
51456
|
try {
|
|
51253
|
-
if (
|
|
51254
|
-
const parsed = JSON.parse(
|
|
51457
|
+
if (existsSync55(p)) {
|
|
51458
|
+
const parsed = JSON.parse(readFileSync60(p, "utf8"));
|
|
51255
51459
|
if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
|
|
51256
51460
|
(v) => Array.isArray(v) && v.every((l) => typeof l === "string")
|
|
51257
51461
|
)) {
|
|
@@ -51300,8 +51504,8 @@ var LEDGER_FILE, OBS_FILE;
|
|
|
51300
51504
|
var init_coverage = __esm({
|
|
51301
51505
|
"src/coverage.ts"() {
|
|
51302
51506
|
init_native_decode();
|
|
51303
|
-
LEDGER_FILE =
|
|
51304
|
-
OBS_FILE =
|
|
51507
|
+
LEDGER_FILE = join54(".himi", "test-ledger.json");
|
|
51508
|
+
OBS_FILE = join54(".himi", "test-observations.json");
|
|
51305
51509
|
}
|
|
51306
51510
|
});
|
|
51307
51511
|
|
|
@@ -51312,16 +51516,16 @@ __export(design_kits_exports, {
|
|
|
51312
51516
|
kitsDir: () => kitsDir,
|
|
51313
51517
|
listKits: () => listKits2
|
|
51314
51518
|
});
|
|
51315
|
-
import { existsSync as
|
|
51316
|
-
import { join as
|
|
51519
|
+
import { existsSync as existsSync56, readFileSync as readFileSync61, readdirSync as readdirSync28 } from "node:fs";
|
|
51520
|
+
import { join as join55, basename as basename14 } from "node:path";
|
|
51317
51521
|
import { fileURLToPath as fileURLToPath21 } from "node:url";
|
|
51318
51522
|
function kitsDir() {
|
|
51319
|
-
return KIT_DIR_CANDIDATES.find((p) =>
|
|
51523
|
+
return KIT_DIR_CANDIDATES.find((p) => existsSync56(p));
|
|
51320
51524
|
}
|
|
51321
51525
|
function listKits2() {
|
|
51322
51526
|
const dir = kitsDir();
|
|
51323
51527
|
if (!dir) return [];
|
|
51324
|
-
return readdirSync28(dir).filter((f) => f.endsWith(".json")).map((f) =>
|
|
51528
|
+
return readdirSync28(dir).filter((f) => f.endsWith(".json")).map((f) => basename14(f, ".json")).sort();
|
|
51325
51529
|
}
|
|
51326
51530
|
function kitReport(name) {
|
|
51327
51531
|
const dir = kitsDir();
|
|
@@ -51340,7 +51544,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
|
|
|
51340
51544
|
if (!kits.includes(name)) {
|
|
51341
51545
|
return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
|
|
51342
51546
|
}
|
|
51343
|
-
const raw =
|
|
51547
|
+
const raw = readFileSync61(join55(dir, `${name}.json`), "utf8");
|
|
51344
51548
|
let parsed;
|
|
51345
51549
|
try {
|
|
51346
51550
|
parsed = JSON.parse(raw);
|
|
@@ -51364,9 +51568,9 @@ var init_design_kits = __esm({
|
|
|
51364
51568
|
"src/design-kits.ts"() {
|
|
51365
51569
|
KIT_DIR_CANDIDATES = [
|
|
51366
51570
|
// in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
|
|
51367
|
-
|
|
51571
|
+
join55(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
|
|
51368
51572
|
// published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
|
|
51369
|
-
|
|
51573
|
+
join55(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
|
|
51370
51574
|
];
|
|
51371
51575
|
}
|
|
51372
51576
|
});
|
|
@@ -51380,11 +51584,11 @@ __export(assets_exports, {
|
|
|
51380
51584
|
removeAssetPayload: () => removeAssetPayload,
|
|
51381
51585
|
verifyReport: () => verifyReport
|
|
51382
51586
|
});
|
|
51383
|
-
import { readFileSync as
|
|
51384
|
-
import { basename as
|
|
51587
|
+
import { readFileSync as readFileSync62 } from "node:fs";
|
|
51588
|
+
import { basename as basename15 } from "node:path";
|
|
51385
51589
|
function declaredAssets(dir) {
|
|
51386
51590
|
return collectAssets(dir).map((a) => {
|
|
51387
|
-
const bytes2 =
|
|
51591
|
+
const bytes2 = readFileSync62(a.path);
|
|
51388
51592
|
return {
|
|
51389
51593
|
name: a.name,
|
|
51390
51594
|
sha256: assetSha256(bytes2),
|
|
@@ -51461,8 +51665,8 @@ function verifyReport(dir, app, manifest) {
|
|
|
51461
51665
|
};
|
|
51462
51666
|
}
|
|
51463
51667
|
function addAssetPayload(manifest, filePath, opts) {
|
|
51464
|
-
const bytes2 =
|
|
51465
|
-
const name = opts.name ??
|
|
51668
|
+
const bytes2 = readFileSync62(filePath);
|
|
51669
|
+
const name = opts.name ?? basename15(filePath);
|
|
51466
51670
|
const sha2565 = assetSha256(bytes2);
|
|
51467
51671
|
const record2 = {
|
|
51468
51672
|
sha256: sha2565,
|
|
@@ -53136,9 +53340,9 @@ __export(run_exports, {
|
|
|
53136
53340
|
runPackage: () => runPackage,
|
|
53137
53341
|
withoutProdServe: () => withoutProdServe
|
|
53138
53342
|
});
|
|
53139
|
-
import { cpSync as cpSync2, existsSync as
|
|
53343
|
+
import { cpSync as cpSync2, existsSync as existsSync57, mkdirSync as mkdirSync26, mkdtempSync as mkdtempSync3, readFileSync as readFileSync63, rmSync as rmSync12, statSync as statSync13 } from "node:fs";
|
|
53140
53344
|
import { networkInterfaces as osNetworkInterfaces, tmpdir as tmpdir4 } from "node:os";
|
|
53141
|
-
import { dirname as dirname29, join as
|
|
53345
|
+
import { dirname as dirname29, join as join56 } from "node:path";
|
|
53142
53346
|
import { fileURLToPath as fileURLToPath22 } from "node:url";
|
|
53143
53347
|
function makePackageRunHandler(opts) {
|
|
53144
53348
|
const store = new FileReleaseStore(opts.releaseRoot);
|
|
@@ -53166,9 +53370,9 @@ async function fetchBytes(url) {
|
|
|
53166
53370
|
}
|
|
53167
53371
|
async function resolvePackage(source, workDir) {
|
|
53168
53372
|
const isUrl2 = /^https?:\/\//i.test(source);
|
|
53169
|
-
if (!isUrl2 &&
|
|
53170
|
-
const appDirManifest =
|
|
53171
|
-
if (
|
|
53373
|
+
if (!isUrl2 && existsSync57(source) && statSync13(source).isDirectory()) {
|
|
53374
|
+
const appDirManifest = join56(source, "release-manifest.json");
|
|
53375
|
+
if (existsSync57(appDirManifest)) {
|
|
53172
53376
|
const opened2 = openPackageDir(source);
|
|
53173
53377
|
if (!opened2.validation.ok) {
|
|
53174
53378
|
throw new Error(`package is not valid:
|
|
@@ -53177,9 +53381,9 @@ async function resolvePackage(source, workDir) {
|
|
|
53177
53381
|
const app2 = opened2.header?.app ?? opened2.manifest?.app;
|
|
53178
53382
|
if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
|
|
53179
53383
|
if (!isSafeAppId(app2)) throw new Error(`${source} declares an unsafe app id ${JSON.stringify(app2)} \u2014 refusing to open it`);
|
|
53180
|
-
const root2 = workDir ?? mkdtempSync3(
|
|
53181
|
-
const target =
|
|
53182
|
-
if (
|
|
53384
|
+
const root2 = workDir ?? mkdtempSync3(join56(tmpdir4(), "himi-run-"));
|
|
53385
|
+
const target = join56(root2, app2);
|
|
53386
|
+
if (join56(source) !== target) {
|
|
53183
53387
|
mkdirSync26(root2, { recursive: true });
|
|
53184
53388
|
rmSync12(target, { recursive: true, force: true });
|
|
53185
53389
|
cpSync2(source, target, { recursive: true });
|
|
@@ -53196,8 +53400,8 @@ async function resolvePackage(source, workDir) {
|
|
|
53196
53400
|
}
|
|
53197
53401
|
throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
|
|
53198
53402
|
}
|
|
53199
|
-
const bytes2 = isUrl2 ? await fetchBytes(source) :
|
|
53200
|
-
const root = workDir ?? mkdtempSync3(
|
|
53403
|
+
const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync63(source);
|
|
53404
|
+
const root = workDir ?? mkdtempSync3(join56(tmpdir4(), "himi-run-"));
|
|
53201
53405
|
const { app, appDir: appDir2 } = unpackTo(bytes2, root);
|
|
53202
53406
|
const opened = openPackageDir(appDir2);
|
|
53203
53407
|
if (!opened.validation.ok) {
|
|
@@ -53220,14 +53424,14 @@ async function loadPreviewAssets() {
|
|
|
53220
53424
|
const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
|
|
53221
53425
|
const here = dirname29(fileURLToPath22(import.meta.url));
|
|
53222
53426
|
const candidates = [
|
|
53223
|
-
|
|
53427
|
+
join56(here, "preview-assets.generated.bin"),
|
|
53224
53428
|
// published: copied next to the bundled CLI
|
|
53225
|
-
|
|
53429
|
+
join56(here, "../../../packages/serve/src/preview-assets.generated.bin")
|
|
53226
53430
|
// in-repo checkout
|
|
53227
53431
|
];
|
|
53228
53432
|
for (const path2 of candidates) {
|
|
53229
|
-
if (!
|
|
53230
|
-
const blob =
|
|
53433
|
+
if (!existsSync57(path2)) continue;
|
|
53434
|
+
const blob = readFileSync63(path2);
|
|
53231
53435
|
return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
|
|
53232
53436
|
}
|
|
53233
53437
|
return /* @__PURE__ */ new Map();
|
|
@@ -53374,9 +53578,9 @@ __export(run_watch_exports, {
|
|
|
53374
53578
|
watchedContentDir: () => watchedContentDir,
|
|
53375
53579
|
writeRunRecord: () => writeRunRecord
|
|
53376
53580
|
});
|
|
53377
|
-
import { closeSync as closeSync2, constants, existsSync as
|
|
53581
|
+
import { closeSync as closeSync2, constants, existsSync as existsSync58, fstatSync, lstatSync as lstatSync10, statSync as statSync14, mkdirSync as mkdirSync27, openSync as openSync2, readFileSync as readFileSync64, realpathSync as realpathSync7, renameSync as renameSync6, rmSync as rmSync13, writeFileSync as writeFileSync23, watch as fsWatch } from "node:fs";
|
|
53378
53582
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
53379
|
-
import { extname as extname4, join as
|
|
53583
|
+
import { extname as extname4, join as join57, resolve as resolve42, sep as sep13 } from "node:path";
|
|
53380
53584
|
function diffReleases(prev, next) {
|
|
53381
53585
|
const bundles = Object.keys(next.bundles).filter((b) => prev.bundles[b]?.sha256 !== next.bundles[b].sha256).sort();
|
|
53382
53586
|
const changedBundles = new Set(bundles);
|
|
@@ -53417,7 +53621,7 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
53417
53621
|
let timer = null;
|
|
53418
53622
|
const pending = /* @__PURE__ */ new Set();
|
|
53419
53623
|
const watcher2 = watch2(dir, { recursive: true }, (_event, file) => {
|
|
53420
|
-
if (!file || ignoredChange(file, (rel) => isDir(
|
|
53624
|
+
if (!file || ignoredChange(file, (rel) => isDir(join57(dir, rel)))) return;
|
|
53421
53625
|
pending.add(file);
|
|
53422
53626
|
if (timer) clearTimeout(timer);
|
|
53423
53627
|
timer = setTimeout(() => {
|
|
@@ -53438,7 +53642,7 @@ function watchedContentDir(source) {
|
|
|
53438
53642
|
if (!source || /^https?:\/\//i.test(source)) return null;
|
|
53439
53643
|
const dir = resolve42(source);
|
|
53440
53644
|
try {
|
|
53441
|
-
return statSync14(dir).isDirectory() &&
|
|
53645
|
+
return statSync14(dir).isDirectory() && existsSync58(join57(dir, "himalaya.content.json")) ? dir : null;
|
|
53442
53646
|
} catch {
|
|
53443
53647
|
return null;
|
|
53444
53648
|
}
|
|
@@ -53495,7 +53699,7 @@ function serialize(task) {
|
|
|
53495
53699
|
});
|
|
53496
53700
|
}
|
|
53497
53701
|
function himiDir(dir) {
|
|
53498
|
-
const root =
|
|
53702
|
+
const root = join57(dir, ".himi");
|
|
53499
53703
|
try {
|
|
53500
53704
|
return lstatSync10(root).isDirectory() ? root : null;
|
|
53501
53705
|
} catch (e) {
|
|
@@ -53507,11 +53711,11 @@ function himiDir(dir) {
|
|
|
53507
53711
|
function writeRunRecord(dir, record2) {
|
|
53508
53712
|
const root = himiDir(dir);
|
|
53509
53713
|
if (!root) return false;
|
|
53510
|
-
const tmp =
|
|
53714
|
+
const tmp = join57(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
|
|
53511
53715
|
try {
|
|
53512
53716
|
writeFileSync23(tmp, `${JSON.stringify(record2, null, 2)}
|
|
53513
53717
|
`, { flag: "wx" });
|
|
53514
|
-
renameSync6(tmp,
|
|
53718
|
+
renameSync6(tmp, join57(root, "run.json"));
|
|
53515
53719
|
} catch (e) {
|
|
53516
53720
|
rmSync13(tmp, { force: true });
|
|
53517
53721
|
throw e;
|
|
@@ -53519,7 +53723,7 @@ function writeRunRecord(dir, record2) {
|
|
|
53519
53723
|
return true;
|
|
53520
53724
|
}
|
|
53521
53725
|
function removeRunRecord(dir, owner) {
|
|
53522
|
-
const root =
|
|
53726
|
+
const root = join57(dir, ".himi");
|
|
53523
53727
|
try {
|
|
53524
53728
|
if (!lstatSync10(root).isDirectory()) return;
|
|
53525
53729
|
} catch {
|
|
@@ -53534,16 +53738,16 @@ function removeRunRecord(dir, owner) {
|
|
|
53534
53738
|
}
|
|
53535
53739
|
if (typeof pid === "number" && pid !== owner) return;
|
|
53536
53740
|
}
|
|
53537
|
-
rmSync13(
|
|
53741
|
+
rmSync13(join57(root, "run.json"), { force: true });
|
|
53538
53742
|
}
|
|
53539
53743
|
function boardFile(dir, pathname) {
|
|
53540
53744
|
let rel = null;
|
|
53541
|
-
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel =
|
|
53542
|
-
else if (pathname === "/__himi/studio/state.js") rel =
|
|
53543
|
-
else if (pathname === "/__himi/studio/timeline.js") rel =
|
|
53745
|
+
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join57("studio", "index.html");
|
|
53746
|
+
else if (pathname === "/__himi/studio/state.js") rel = join57("studio", "state.js");
|
|
53747
|
+
else if (pathname === "/__himi/studio/timeline.js") rel = join57("studio", "timeline.js");
|
|
53544
53748
|
else {
|
|
53545
53749
|
const m = /^\/__himi\/history\/([0-9a-f]{64}\.(png|jpg|gif|webp))$/.exec(pathname);
|
|
53546
|
-
if (m) rel =
|
|
53750
|
+
if (m) rel = join57("history", m[1]);
|
|
53547
53751
|
}
|
|
53548
53752
|
if (!rel) return null;
|
|
53549
53753
|
const bytes2 = readConfined(resolve42(dir, ".himi"), rel);
|
|
@@ -53559,7 +53763,7 @@ function readConfined(root, rel) {
|
|
|
53559
53763
|
const parts = rel.split(sep13);
|
|
53560
53764
|
let at = root;
|
|
53561
53765
|
for (let i = 0; i < parts.length; i++) {
|
|
53562
|
-
at =
|
|
53766
|
+
at = join57(at, parts[i]);
|
|
53563
53767
|
const st = lstatSync10(at);
|
|
53564
53768
|
if (st.isSymbolicLink() || !(i === parts.length - 1 ? st.isFile() : st.isDirectory())) return null;
|
|
53565
53769
|
}
|
|
@@ -53568,7 +53772,7 @@ function readConfined(root, rel) {
|
|
|
53568
53772
|
const fd = openSync2(at, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
53569
53773
|
try {
|
|
53570
53774
|
if (!fstatSync(fd).isFile()) return null;
|
|
53571
|
-
return
|
|
53775
|
+
return readFileSync64(fd);
|
|
53572
53776
|
} finally {
|
|
53573
53777
|
closeSync2(fd);
|
|
53574
53778
|
}
|
|
@@ -53620,7 +53824,7 @@ __export(run_browser_exports, {
|
|
|
53620
53824
|
runInBrowser: () => runInBrowser
|
|
53621
53825
|
});
|
|
53622
53826
|
import { createServer as createServer5 } from "node:http";
|
|
53623
|
-
import { existsSync as
|
|
53827
|
+
import { existsSync as existsSync59, readFileSync as readFileSync65 } from "node:fs";
|
|
53624
53828
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
53625
53829
|
import { dirname as dirname30, resolve as resolve43 } from "node:path";
|
|
53626
53830
|
import { fileURLToPath as fileURLToPath23 } from "node:url";
|
|
@@ -53628,7 +53832,7 @@ function stagedDir() {
|
|
|
53628
53832
|
return process.env.HIMI_BROWSER_PLANE_OUT ? resolve43(process.env.HIMI_BROWSER_PLANE_OUT) : resolve43(REPO, "packages", "serve", "dist", "browser-plane");
|
|
53629
53833
|
}
|
|
53630
53834
|
function missingStaged() {
|
|
53631
|
-
return [...SERVED].filter((f) => !
|
|
53835
|
+
return [...SERVED].filter((f) => !existsSync59(resolve43(stagedDir(), f))).sort();
|
|
53632
53836
|
}
|
|
53633
53837
|
function ensureBrowserPlaneStaged() {
|
|
53634
53838
|
if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
|
|
@@ -53713,7 +53917,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
53713
53917
|
}
|
|
53714
53918
|
const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
|
|
53715
53919
|
if (SERVED.has(name)) {
|
|
53716
|
-
if (!
|
|
53920
|
+
if (!existsSync59(resolve43(stagedDir(), name))) {
|
|
53717
53921
|
const restaged = ensureBrowserPlaneStaged();
|
|
53718
53922
|
if (!restaged.ok) {
|
|
53719
53923
|
res.writeHead(503, { "content-type": "application/json" });
|
|
@@ -53723,7 +53927,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
53723
53927
|
}
|
|
53724
53928
|
let bytes2;
|
|
53725
53929
|
try {
|
|
53726
|
-
bytes2 =
|
|
53930
|
+
bytes2 = readFileSync65(resolve43(stagedDir(), name));
|
|
53727
53931
|
} catch (e) {
|
|
53728
53932
|
res.writeHead(503, { "content-type": "application/json" });
|
|
53729
53933
|
res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
|
|
@@ -54184,11 +54388,11 @@ __export(preflight_exports, {
|
|
|
54184
54388
|
parseStoreConfig: () => parseStoreConfig,
|
|
54185
54389
|
requireEnv: () => requireEnv
|
|
54186
54390
|
});
|
|
54187
|
-
import { existsSync as
|
|
54188
|
-
import { isAbsolute as
|
|
54391
|
+
import { existsSync as existsSync60, readFileSync as readFileSync66 } from "node:fs";
|
|
54392
|
+
import { isAbsolute as isAbsolute5, relative as relative11, resolve as resolve44 } from "node:path";
|
|
54189
54393
|
function isInsideRepo(p) {
|
|
54190
|
-
const rel =
|
|
54191
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
54394
|
+
const rel = relative11(REPO_ROOT3, resolve44(p));
|
|
54395
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute5(rel);
|
|
54192
54396
|
}
|
|
54193
54397
|
function assertCredentialOutsideRepo(label2, p) {
|
|
54194
54398
|
if (isInsideRepo(p)) {
|
|
@@ -54241,10 +54445,10 @@ function parseStoreConfig(text5) {
|
|
|
54241
54445
|
}
|
|
54242
54446
|
function loadStoreConfig(app) {
|
|
54243
54447
|
const p = storeConfigPath(app);
|
|
54244
|
-
if (!
|
|
54448
|
+
if (!existsSync60(p)) {
|
|
54245
54449
|
throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
|
|
54246
54450
|
}
|
|
54247
|
-
return parseStoreConfig(
|
|
54451
|
+
return parseStoreConfig(readFileSync66(p, "utf8"));
|
|
54248
54452
|
}
|
|
54249
54453
|
var init_preflight = __esm({
|
|
54250
54454
|
"../store-release/preflight.ts"() {
|
|
@@ -54263,19 +54467,19 @@ __export(credential_profile_exports, {
|
|
|
54263
54467
|
profilePath: () => profilePath,
|
|
54264
54468
|
resolveStoreCredentials: () => resolveStoreCredentials
|
|
54265
54469
|
});
|
|
54266
|
-
import { existsSync as
|
|
54470
|
+
import { existsSync as existsSync61, readFileSync as readFileSync67 } from "node:fs";
|
|
54267
54471
|
import { homedir as homedir5 } from "node:os";
|
|
54268
|
-
import { join as
|
|
54472
|
+
import { join as join58 } from "node:path";
|
|
54269
54473
|
function credentialsDir(home = homedir5()) {
|
|
54270
|
-
return
|
|
54474
|
+
return join58(home, ".himalaya", "store-credentials");
|
|
54271
54475
|
}
|
|
54272
54476
|
function profilePath(name, home = homedir5()) {
|
|
54273
54477
|
if (!PROFILE_NAME.test(name)) {
|
|
54274
54478
|
throw new Error(
|
|
54275
|
-
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${
|
|
54479
|
+
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join58(credentialsDir(home), "<name>.json")}; it is never a path.`
|
|
54276
54480
|
);
|
|
54277
54481
|
}
|
|
54278
|
-
return
|
|
54482
|
+
return join58(credentialsDir(home), `${name}.json`);
|
|
54279
54483
|
}
|
|
54280
54484
|
function parseProfile(text5, label2) {
|
|
54281
54485
|
let doc;
|
|
@@ -54306,8 +54510,8 @@ function resolveStoreCredentials(opts) {
|
|
|
54306
54510
|
const { app, cfg } = opts;
|
|
54307
54511
|
const env = opts.env ?? process.env;
|
|
54308
54512
|
const home = opts.home ?? homedir5();
|
|
54309
|
-
const read = opts.readProfile ?? ((p) =>
|
|
54310
|
-
const exists = opts.profileExists ??
|
|
54513
|
+
const read = opts.readProfile ?? ((p) => readFileSync67(p, "utf8"));
|
|
54514
|
+
const exists = opts.profileExists ?? existsSync61;
|
|
54311
54515
|
const ios = cfg.ios ?? {};
|
|
54312
54516
|
const flagName = opts.profileFlag?.trim();
|
|
54313
54517
|
const named = namedProfile(cfg, opts.profileFlag);
|
|
@@ -54387,9 +54591,9 @@ __export(preflight_app_exports, {
|
|
|
54387
54591
|
preflightApp: () => preflightApp,
|
|
54388
54592
|
profileAccount: () => profileAccount
|
|
54389
54593
|
});
|
|
54390
|
-
import { readFileSync as
|
|
54594
|
+
import { readFileSync as readFileSync68, existsSync as existsSync62, readdirSync as readdirSync29, statSync as statSync15 } from "node:fs";
|
|
54391
54595
|
import { createHash as createHash27 } from "node:crypto";
|
|
54392
|
-
import { join as
|
|
54596
|
+
import { join as join59 } from "node:path";
|
|
54393
54597
|
function analyze(projectYml, storeConfig, icon, account) {
|
|
54394
54598
|
const f = [];
|
|
54395
54599
|
const has = (re, s) => re.test(s);
|
|
@@ -54453,13 +54657,13 @@ function profileAccount(app, storeConfig, opts = {}) {
|
|
|
54453
54657
|
}
|
|
54454
54658
|
}
|
|
54455
54659
|
async function preflightApp(app, opts = {}) {
|
|
54456
|
-
const projectYml =
|
|
54457
|
-
const storeConfig =
|
|
54660
|
+
const projectYml = existsSync62(iosProjectYml(app)) ? readFileSync68(iosProjectYml(app), "utf8") : "";
|
|
54661
|
+
const storeConfig = existsSync62(storeConfigPath(app)) ? readFileSync68(storeConfigPath(app), "utf8") : "";
|
|
54458
54662
|
if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
|
|
54459
54663
|
const findings = analyze(
|
|
54460
54664
|
projectYml,
|
|
54461
54665
|
storeConfig,
|
|
54462
|
-
await appIconState(
|
|
54666
|
+
await appIconState(join59(appDir(app), "ios")),
|
|
54463
54667
|
profileAccount(app, storeConfig, opts)
|
|
54464
54668
|
);
|
|
54465
54669
|
findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
|
|
@@ -54488,17 +54692,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
|
|
|
54488
54692
|
return f;
|
|
54489
54693
|
}
|
|
54490
54694
|
function appLevelMetadataFiles(app, locale = "en-US") {
|
|
54491
|
-
const root =
|
|
54695
|
+
const root = join59(storeDir(app), "metadata");
|
|
54492
54696
|
const out = /* @__PURE__ */ new Set();
|
|
54493
|
-
if (
|
|
54697
|
+
if (existsSync62(root)) {
|
|
54494
54698
|
for (const n of readdirSync29(root)) if (n.endsWith(".txt")) out.add(n);
|
|
54495
54699
|
}
|
|
54496
|
-
if (
|
|
54700
|
+
if (existsSync62(join59(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
|
|
54497
54701
|
return out;
|
|
54498
54702
|
}
|
|
54499
54703
|
function reviewInfoFiles(app) {
|
|
54500
|
-
const dir =
|
|
54501
|
-
if (!
|
|
54704
|
+
const dir = join59(storeDir(app), "review_information");
|
|
54705
|
+
if (!existsSync62(dir)) return /* @__PURE__ */ new Set();
|
|
54502
54706
|
return new Set(readdirSync29(dir).filter((n) => n.endsWith(".txt")));
|
|
54503
54707
|
}
|
|
54504
54708
|
function isValidAppStoreSize(w, h) {
|
|
@@ -54608,12 +54812,12 @@ function analyzePlayListing(assets) {
|
|
|
54608
54812
|
return f;
|
|
54609
54813
|
}
|
|
54610
54814
|
function playListingAssets(app, locale = "en-US") {
|
|
54611
|
-
const dir =
|
|
54815
|
+
const dir = join59(storeDir(app), "play", locale, "images");
|
|
54612
54816
|
const read = (names) => {
|
|
54613
54817
|
for (const name of names) {
|
|
54614
|
-
const p =
|
|
54818
|
+
const p = join59(dir, name);
|
|
54615
54819
|
try {
|
|
54616
|
-
if (statSync15(p).isFile()) return { name, bytes:
|
|
54820
|
+
if (statSync15(p).isFile()) return { name, bytes: readFileSync68(p) };
|
|
54617
54821
|
} catch {
|
|
54618
54822
|
}
|
|
54619
54823
|
}
|
|
@@ -54644,26 +54848,26 @@ function analyzeListing(metaFiles, shots) {
|
|
|
54644
54848
|
return f;
|
|
54645
54849
|
}
|
|
54646
54850
|
function metadataFilesPresent(app, locale = "en-US") {
|
|
54647
|
-
const dir =
|
|
54648
|
-
if (!
|
|
54851
|
+
const dir = join59(storeDir(app), "metadata", locale);
|
|
54852
|
+
if (!existsSync62(dir)) return /* @__PURE__ */ new Set();
|
|
54649
54853
|
return new Set(readdirSync29(dir).filter((n) => n.endsWith(".txt")));
|
|
54650
54854
|
}
|
|
54651
54855
|
function listScreenshots(app, locale = "en-US") {
|
|
54652
54856
|
const out = [];
|
|
54653
|
-
const flat =
|
|
54654
|
-
if (
|
|
54857
|
+
const flat = join59(storeDir(app), "screenshots", locale);
|
|
54858
|
+
if (existsSync62(flat)) {
|
|
54655
54859
|
for (const png of readdirSync29(flat).filter((n) => n.endsWith(".png"))) {
|
|
54656
|
-
const sz = pngSize(
|
|
54860
|
+
const sz = pngSize(readFileSync68(join59(flat, png)));
|
|
54657
54861
|
if (sz) out.push({ name: png, w: sz.w, h: sz.h });
|
|
54658
54862
|
}
|
|
54659
54863
|
}
|
|
54660
|
-
const legacy =
|
|
54661
|
-
if (
|
|
54864
|
+
const legacy = join59(storeDir(app), "metadata", locale, "screenshots");
|
|
54865
|
+
if (existsSync62(legacy)) {
|
|
54662
54866
|
for (const deviceDir of readdirSync29(legacy)) {
|
|
54663
|
-
const d =
|
|
54867
|
+
const d = join59(legacy, deviceDir);
|
|
54664
54868
|
if (!statSync15(d).isDirectory()) continue;
|
|
54665
54869
|
for (const png of readdirSync29(d).filter((n) => n.endsWith(".png"))) {
|
|
54666
|
-
const sz = pngSize(
|
|
54870
|
+
const sz = pngSize(readFileSync68(join59(d, png)));
|
|
54667
54871
|
if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
|
|
54668
54872
|
}
|
|
54669
54873
|
}
|
|
@@ -54671,13 +54875,13 @@ function listScreenshots(app, locale = "en-US") {
|
|
|
54671
54875
|
return out;
|
|
54672
54876
|
}
|
|
54673
54877
|
function placeholderHashes2() {
|
|
54674
|
-
const templateIos =
|
|
54675
|
-
if (!
|
|
54878
|
+
const templateIos = join59(appDir("_template"), "ios");
|
|
54879
|
+
if (!existsSync62(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
|
|
54676
54880
|
for (const target of readdirSync29(templateIos)) {
|
|
54677
|
-
const p =
|
|
54881
|
+
const p = join59(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
54678
54882
|
try {
|
|
54679
54883
|
if (!statSync15(p).isFile()) continue;
|
|
54680
|
-
return [LEGACY_PLACEHOLDER_SHA2562, createHash27("sha256").update(
|
|
54884
|
+
return [LEGACY_PLACEHOLDER_SHA2562, createHash27("sha256").update(readFileSync68(p)).digest("hex")];
|
|
54681
54885
|
} catch {
|
|
54682
54886
|
}
|
|
54683
54887
|
}
|
|
@@ -54708,12 +54912,12 @@ async function pixelIssues(bytes2) {
|
|
|
54708
54912
|
}
|
|
54709
54913
|
}
|
|
54710
54914
|
async function appIconState(iosDir) {
|
|
54711
|
-
if (!
|
|
54915
|
+
if (!existsSync62(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
|
|
54712
54916
|
for (const target of readdirSync29(iosDir)) {
|
|
54713
|
-
const p =
|
|
54917
|
+
const p = join59(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
54714
54918
|
try {
|
|
54715
54919
|
if (!statSync15(p).isFile()) continue;
|
|
54716
|
-
const bytes2 =
|
|
54920
|
+
const bytes2 = readFileSync68(p);
|
|
54717
54921
|
const hash = createHash27("sha256").update(bytes2).digest("hex");
|
|
54718
54922
|
const pixels = await pixelIssues(bytes2);
|
|
54719
54923
|
return {
|
|
@@ -54785,7 +54989,7 @@ __export(version_exports, {
|
|
|
54785
54989
|
setAndroidVersion: () => setAndroidVersion,
|
|
54786
54990
|
setIosVersion: () => setIosVersion
|
|
54787
54991
|
});
|
|
54788
|
-
import { readFileSync as
|
|
54992
|
+
import { readFileSync as readFileSync69, writeFileSync as writeFileSync24 } from "node:fs";
|
|
54789
54993
|
function readIosVersion(projectYml) {
|
|
54790
54994
|
const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
|
|
54791
54995
|
const build2 = matchScalar(projectYml, "CFBundleVersion");
|
|
@@ -54843,8 +55047,8 @@ function setAndroidVersion(gradle, v) {
|
|
|
54843
55047
|
function bumpVersion(app, opts) {
|
|
54844
55048
|
const iosPath = iosProjectYml(app);
|
|
54845
55049
|
const gradlePath = androidGradle(app);
|
|
54846
|
-
const iosYml =
|
|
54847
|
-
const gradle =
|
|
55050
|
+
const iosYml = readFileSync69(iosPath, "utf8");
|
|
55051
|
+
const gradle = readFileSync69(gradlePath, "utf8");
|
|
54848
55052
|
const current = readIosVersion(iosYml);
|
|
54849
55053
|
const next = {
|
|
54850
55054
|
marketing: opts.marketing ?? current.marketing,
|
|
@@ -54861,7 +55065,7 @@ var init_version = __esm({
|
|
|
54861
55065
|
});
|
|
54862
55066
|
|
|
54863
55067
|
// ../store-release/register-bundle.ts
|
|
54864
|
-
import { readFileSync as
|
|
55068
|
+
import { readFileSync as readFileSync70 } from "node:fs";
|
|
54865
55069
|
import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
|
|
54866
55070
|
function b64url2(b) {
|
|
54867
55071
|
return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
@@ -54879,7 +55083,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
|
|
|
54879
55083
|
async function registerBundleId(opts) {
|
|
54880
55084
|
const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
54881
55085
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
54882
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
55086
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync70(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
54883
55087
|
const res = await fetch(`${ASC_API}/v1/bundleIds`, {
|
|
54884
55088
|
method: "POST",
|
|
54885
55089
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
@@ -54933,7 +55137,7 @@ __export(asc_status_exports, {
|
|
|
54933
55137
|
ascStatus: () => ascStatus,
|
|
54934
55138
|
buildVerdict: () => buildVerdict
|
|
54935
55139
|
});
|
|
54936
|
-
import { readFileSync as
|
|
55140
|
+
import { readFileSync as readFileSync71 } from "node:fs";
|
|
54937
55141
|
function buildVerdict(builds) {
|
|
54938
55142
|
if (!builds.length) {
|
|
54939
55143
|
return "NO builds registered \u2014 if you uploaded recently and it's been >15 min, the binary was REJECTED IN PROCESSING (reason is email-only; run validate-binary.ts / scan-purpose-strings.ts to reproduce it).";
|
|
@@ -54947,7 +55151,7 @@ function buildVerdict(builds) {
|
|
|
54947
55151
|
function client(creds) {
|
|
54948
55152
|
const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
54949
55153
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
54950
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
55154
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync71(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
54951
55155
|
return async (path2) => {
|
|
54952
55156
|
const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
|
|
54953
55157
|
return { status: r.status, json: await r.json().catch(() => ({})) };
|
|
@@ -55107,7 +55311,7 @@ __export(secrets_exports, {
|
|
|
55107
55311
|
runRemoteSecretsCommand: () => runRemoteSecretsCommand,
|
|
55108
55312
|
runSecretsCommand: () => runSecretsCommand
|
|
55109
55313
|
});
|
|
55110
|
-
import { readFileSync as
|
|
55314
|
+
import { readFileSync as readFileSync72 } from "node:fs";
|
|
55111
55315
|
function environment(value) {
|
|
55112
55316
|
if (value === "preview" || value === "production") return value;
|
|
55113
55317
|
throw new Error("--environment must be preview or production");
|
|
@@ -55138,7 +55342,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
|
|
|
55138
55342
|
io.log(JSON.stringify(await vault.list({ app, environment: env })));
|
|
55139
55343
|
return 0;
|
|
55140
55344
|
}
|
|
55141
|
-
const value = options.readValue ? options.readValue() :
|
|
55345
|
+
const value = options.readValue ? options.readValue() : readFileSync72(0, "utf8").replace(/\r?\n$/, "");
|
|
55142
55346
|
if (operation === "set") await vault.set({ app, environment: env, name, value });
|
|
55143
55347
|
else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
|
|
55144
55348
|
else throw new Error(`unknown secrets operation ${operation}`);
|
|
@@ -55167,7 +55371,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
|
|
|
55167
55371
|
}
|
|
55168
55372
|
let body;
|
|
55169
55373
|
if (operation !== "list") {
|
|
55170
|
-
const value = options.readValue ? options.readValue() :
|
|
55374
|
+
const value = options.readValue ? options.readValue() : readFileSync72(0, "utf8").replace(/\r?\n$/, "");
|
|
55171
55375
|
body = JSON.stringify({ value });
|
|
55172
55376
|
}
|
|
55173
55377
|
const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
|
|
@@ -55203,15 +55407,15 @@ __export(notify_exports, {
|
|
|
55203
55407
|
runNotify: () => runNotify,
|
|
55204
55408
|
saveAdminSession: () => saveAdminSession
|
|
55205
55409
|
});
|
|
55206
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync28, readFileSync as
|
|
55410
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync28, readFileSync as readFileSync73, writeFileSync as writeFileSync25 } from "node:fs";
|
|
55207
55411
|
import { homedir as homedir6 } from "node:os";
|
|
55208
|
-
import { dirname as dirname32, join as
|
|
55412
|
+
import { dirname as dirname32, join as join60 } from "node:path";
|
|
55209
55413
|
function defaultSessionsPath() {
|
|
55210
|
-
return process.env.HIMI_ADMIN_SESSIONS_FILE ??
|
|
55414
|
+
return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join60(homedir6(), ".himalaya", "admin-sessions.json");
|
|
55211
55415
|
}
|
|
55212
55416
|
function loadSessionsFile(path2 = defaultSessionsPath()) {
|
|
55213
55417
|
try {
|
|
55214
|
-
return JSON.parse(
|
|
55418
|
+
return JSON.parse(readFileSync73(path2, "utf8"));
|
|
55215
55419
|
} catch {
|
|
55216
55420
|
return {};
|
|
55217
55421
|
}
|
|
@@ -56341,7 +56545,7 @@ function deriveAdoptedCmsCollections(cms) {
|
|
|
56341
56545
|
return { collections, dropped };
|
|
56342
56546
|
}
|
|
56343
56547
|
function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
56344
|
-
const
|
|
56548
|
+
const appName2 = deriveAppName(ctx, overrides.appName);
|
|
56345
56549
|
const supportUrl = clean(overrides.supportUrl) || clean(ctx.url.primary);
|
|
56346
56550
|
const privacyUrl = clean(overrides.privacyUrl);
|
|
56347
56551
|
const termsUrl = clean(overrides.termsUrl);
|
|
@@ -56361,8 +56565,8 @@ function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
|
56361
56565
|
// empty; either way the key exists and the shell's list never survives the merge.
|
|
56362
56566
|
cmsCollections: [],
|
|
56363
56567
|
identity: {
|
|
56364
|
-
appName,
|
|
56365
|
-
businessName: clean(ctx.identity.businessName) ||
|
|
56568
|
+
appName: appName2,
|
|
56569
|
+
businessName: clean(ctx.identity.businessName) || appName2,
|
|
56366
56570
|
tagline: clean(overrides.tagline) || clean(ctx.identity.description),
|
|
56367
56571
|
// "" means UNKNOWN here, with `missing` above as the signal — the published overlay's
|
|
56368
56572
|
// documented shape. Keeping an unknown url out of a MERGE is `apply.ts`'s job, at the
|
|
@@ -56372,7 +56576,7 @@ function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
|
56372
56576
|
termsUrl
|
|
56373
56577
|
}
|
|
56374
56578
|
};
|
|
56375
|
-
return { appName, iconSource: deriveIconSource(ctx), provisioning, missing };
|
|
56579
|
+
return { appName: appName2, iconSource: deriveIconSource(ctx), provisioning, missing };
|
|
56376
56580
|
}
|
|
56377
56581
|
function bounded(s, max) {
|
|
56378
56582
|
if (s.length <= max) return s;
|
|
@@ -58468,11 +58672,11 @@ function crawledPageName(look, page) {
|
|
|
58468
58672
|
const hit = (page?.pageId ? sitePages.find((p) => p.pageId === page.pageId) : void 0) ?? (look.mainPageId ? sitePages.find((p) => p.pageId === look.mainPageId) : void 0) ?? sitePages.find((p) => p.slug === "home");
|
|
58469
58673
|
return hit?.title.trim() ?? "";
|
|
58470
58674
|
}
|
|
58471
|
-
function guessedNameWarning(
|
|
58472
|
-
const from = crawledTitle && crawledTitle !==
|
|
58675
|
+
function guessedNameWarning(appName2, crawledTitle, ownerLookupError) {
|
|
58676
|
+
const from = crawledTitle && crawledTitle !== appName2 ? ` off the crawled page title "${crawledTitle}"` : " from the site crawl";
|
|
58473
58677
|
const why = ownerLookupError ? `the owner site-properties read FAILED (${ownerLookupError}), so the owner-entered name was never read` : "no owner token was available, so site-properties was never read";
|
|
58474
58678
|
const remedy = ownerLookupError ? "resolve that failure and re-run the same owner-authenticated command" : "re-run with owner auth (`himi site analyze --site <msid>`)";
|
|
58475
|
-
return `identity.appName "${
|
|
58679
|
+
return `identity.appName "${appName2}" is a GUESS, read${from} rather than from the owner-entered business name \u2014 ${why}. --apply writes it into provisioning.json as-is and it reaches both app stores verbatim, so check it: ${remedy}, or set identity.appName in provisioning.json yourself.`;
|
|
58476
58680
|
}
|
|
58477
58681
|
function mergeLookFromPublished(look, published, siteUrl) {
|
|
58478
58682
|
const sitePages = withPageUrls(
|
|
@@ -58980,7 +59184,7 @@ var init_brand_font = __esm({
|
|
|
58980
59184
|
|
|
58981
59185
|
// src/site-analyze/write-artifacts.ts
|
|
58982
59186
|
import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync26 } from "node:fs";
|
|
58983
|
-
import { join as
|
|
59187
|
+
import { join as join61 } from "node:path";
|
|
58984
59188
|
function attachVeloSources(book, sources, put) {
|
|
58985
59189
|
const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
|
|
58986
59190
|
for (const f of book.velo.files) {
|
|
@@ -59135,12 +59339,12 @@ async function downloadMedia(book, fetchImpl, put) {
|
|
|
59135
59339
|
}
|
|
59136
59340
|
async function writeBusinessBook(result, opts) {
|
|
59137
59341
|
const out = opts.outDir;
|
|
59138
|
-
mkdirSync29(
|
|
59139
|
-
mkdirSync29(
|
|
59342
|
+
mkdirSync29(join61(out, "evidence/pages"), { recursive: true });
|
|
59343
|
+
mkdirSync29(join61(out, "media/catalog"), { recursive: true });
|
|
59140
59344
|
const files = [];
|
|
59141
59345
|
const put = (rel, body) => {
|
|
59142
|
-
const p =
|
|
59143
|
-
mkdirSync29(
|
|
59346
|
+
const p = join61(out, rel);
|
|
59347
|
+
mkdirSync29(join61(p, ".."), { recursive: true });
|
|
59144
59348
|
writeFileSync26(p, body);
|
|
59145
59349
|
files.push(rel);
|
|
59146
59350
|
};
|
|
@@ -59234,8 +59438,8 @@ var init_customer_build = __esm({
|
|
|
59234
59438
|
});
|
|
59235
59439
|
|
|
59236
59440
|
// src/site-analyze/apply.ts
|
|
59237
|
-
import { existsSync as
|
|
59238
|
-
import { dirname as dirname33, isAbsolute as
|
|
59441
|
+
import { existsSync as existsSync63, readFileSync as readFileSync74, writeFileSync as writeFileSync27, copyFileSync as copyFileSync3, mkdirSync as mkdirSync30, realpathSync as realpathSync8, statSync as statSync16 } from "node:fs";
|
|
59442
|
+
import { dirname as dirname33, isAbsolute as isAbsolute6, join as join62, resolve as resolve45, sep as sep14 } from "node:path";
|
|
59239
59443
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
59240
59444
|
function unpairedRedirectNote(overlay) {
|
|
59241
59445
|
if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
|
|
@@ -59250,7 +59454,7 @@ function committedShellProvisioning(path2) {
|
|
|
59250
59454
|
function findRepoRoot(cwd) {
|
|
59251
59455
|
let dir = cwd;
|
|
59252
59456
|
for (let i = 0; i < 8; i++) {
|
|
59253
|
-
if (SHELL_NAMES2.some((name) =>
|
|
59457
|
+
if (SHELL_NAMES2.some((name) => existsSync63(join62(dir, shellAppDir(name), "package.json")))) return dir;
|
|
59254
59458
|
const next = dirname33(dir);
|
|
59255
59459
|
if (next === dir) break;
|
|
59256
59460
|
dir = next;
|
|
@@ -59319,24 +59523,24 @@ function mergeCustomerOwned(committed, overlay) {
|
|
|
59319
59523
|
}
|
|
59320
59524
|
function buildMergedContract(options) {
|
|
59321
59525
|
const { appDir: appDir2, packageDir, overlay } = options;
|
|
59322
|
-
const committedPath =
|
|
59323
|
-
if (!
|
|
59526
|
+
const committedPath = join62(appDir2, "provisioning.json");
|
|
59527
|
+
if (!existsSync63(committedPath)) {
|
|
59324
59528
|
throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
|
|
59325
59529
|
}
|
|
59326
|
-
const committed = JSON.parse(
|
|
59530
|
+
const committed = JSON.parse(readFileSync74(committedPath, "utf8"));
|
|
59327
59531
|
const merged = mergeCustomerOwned(committed, overlay);
|
|
59328
59532
|
const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
|
|
59329
59533
|
const branding = merged.branding ?? {};
|
|
59330
59534
|
const staged = [];
|
|
59331
59535
|
const contained = (root, rel) => {
|
|
59332
|
-
if (
|
|
59536
|
+
if (isAbsolute6(rel)) return void 0;
|
|
59333
59537
|
const full = resolve45(root, rel);
|
|
59334
59538
|
return full.startsWith(resolve45(root) + sep14) ? full : void 0;
|
|
59335
59539
|
};
|
|
59336
59540
|
const stage = (fromRel, toRel) => {
|
|
59337
59541
|
const from = contained(packageDir, fromRel);
|
|
59338
|
-
const to = contained(
|
|
59339
|
-
if (!from || !to || !
|
|
59542
|
+
const to = contained(join62(appDir2, STAGED), toRel.slice(STAGED.length + 1));
|
|
59543
|
+
if (!from || !to || !existsSync63(from)) return void 0;
|
|
59340
59544
|
let real;
|
|
59341
59545
|
let realRoot;
|
|
59342
59546
|
try {
|
|
@@ -59358,11 +59562,11 @@ function buildMergedContract(options) {
|
|
|
59358
59562
|
};
|
|
59359
59563
|
const icon = stage("media/icon.png", `${STAGED}/icon.png`);
|
|
59360
59564
|
if (icon) branding.appIconPath = icon;
|
|
59361
|
-
const facesPath =
|
|
59362
|
-
if (
|
|
59565
|
+
const facesPath = join62(packageDir, "media/fonts/faces.json");
|
|
59566
|
+
if (existsSync63(facesPath)) {
|
|
59363
59567
|
let faces = [];
|
|
59364
59568
|
try {
|
|
59365
|
-
const parsed = JSON.parse(
|
|
59569
|
+
const parsed = JSON.parse(readFileSync74(facesPath, "utf8"));
|
|
59366
59570
|
faces = Array.isArray(parsed) ? parsed : [];
|
|
59367
59571
|
} catch {
|
|
59368
59572
|
faces = [];
|
|
@@ -59383,9 +59587,9 @@ function buildMergedContract(options) {
|
|
|
59383
59587
|
merged.branding = branding;
|
|
59384
59588
|
const body = `${JSON.stringify(merged, null, 2)}
|
|
59385
59589
|
`;
|
|
59386
|
-
const path2 =
|
|
59590
|
+
const path2 = join62(packageDir, "provisioning.contract.json");
|
|
59387
59591
|
writeFileSync27(path2, body);
|
|
59388
|
-
const localPath =
|
|
59592
|
+
const localPath = join62(appDir2, LOCAL_CONTRACT_REL);
|
|
59389
59593
|
mkdirSync30(dirname33(localPath), { recursive: true });
|
|
59390
59594
|
writeFileSync27(localPath, body);
|
|
59391
59595
|
staged.push(localPath);
|
|
@@ -59420,10 +59624,10 @@ function catalogTypography(overlay, template) {
|
|
|
59420
59624
|
function staticFaqFor(overlay, overlayPath) {
|
|
59421
59625
|
const own3 = overlay.faq;
|
|
59422
59626
|
if (own3 !== void 0) return deriveStaticFaq(own3);
|
|
59423
|
-
const bookPath =
|
|
59424
|
-
if (!
|
|
59627
|
+
const bookPath = join62(dirname33(resolve45(overlayPath)), "book.json");
|
|
59628
|
+
if (!existsSync63(bookPath)) return void 0;
|
|
59425
59629
|
try {
|
|
59426
|
-
const book = JSON.parse(
|
|
59630
|
+
const book = JSON.parse(readFileSync74(bookPath, "utf8"));
|
|
59427
59631
|
const copy = book?.copy;
|
|
59428
59632
|
if (!copy || typeof copy !== "object" || copy.unavailable) return void 0;
|
|
59429
59633
|
const pairs = deriveStaticFaq(copy.faq);
|
|
@@ -59437,8 +59641,8 @@ async function applyOverlays(input) {
|
|
|
59437
59641
|
const cwd = resolve45(input.cwd);
|
|
59438
59642
|
const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
|
|
59439
59643
|
assertKnownShell(shell);
|
|
59440
|
-
const overlay = JSON.parse(
|
|
59441
|
-
const tokens = JSON.parse(
|
|
59644
|
+
const overlay = JSON.parse(readFileSync74(input.overlayPath, "utf8"));
|
|
59645
|
+
const tokens = JSON.parse(readFileSync74(input.tokensPath, "utf8"));
|
|
59442
59646
|
const faq = staticFaqFor(overlay, input.overlayPath);
|
|
59443
59647
|
if (faq !== void 0) overlay.faq = faq;
|
|
59444
59648
|
const wrote = [];
|
|
@@ -59450,9 +59654,9 @@ async function applyOverlays(input) {
|
|
|
59450
59654
|
`shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
|
|
59451
59655
|
);
|
|
59452
59656
|
}
|
|
59453
|
-
const appDir2 =
|
|
59454
|
-
const committedPath =
|
|
59455
|
-
const committedSite =
|
|
59657
|
+
const appDir2 = join62(repoRoot2, shellAppDir(shell));
|
|
59658
|
+
const committedPath = join62(appDir2, "provisioning.json");
|
|
59659
|
+
const committedSite = existsSync63(committedPath) ? JSON.parse(readFileSync74(committedPath, "utf8")).site : void 0;
|
|
59456
59660
|
if (committedSite !== void 0 && overlay.site === void 0) {
|
|
59457
59661
|
throw new Error(
|
|
59458
59662
|
`shell "${shell}" is a site shell: its contract names the customer's website (a \`site\` block), which this analysis does not produce yet. Write the site block into a contract and run \`npm run prepare:customer -- --contract <file>\` in ${shellAppDir(shell)} (or \`himi dist --shell ${shell}\`).`
|
|
@@ -59479,11 +59683,11 @@ async function applyOverlays(input) {
|
|
|
59479
59683
|
note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
|
|
59480
59684
|
};
|
|
59481
59685
|
}
|
|
59482
|
-
const pkgProv =
|
|
59686
|
+
const pkgProv = join62(cwd, "provisioning.json");
|
|
59483
59687
|
assertNotCommitted(pkgProv, input.forbiddenProvisioning);
|
|
59484
59688
|
let packageFaq = faq;
|
|
59485
|
-
if (
|
|
59486
|
-
const cur = JSON.parse(
|
|
59689
|
+
if (existsSync63(pkgProv)) {
|
|
59690
|
+
const cur = JSON.parse(readFileSync74(pkgProv, "utf8"));
|
|
59487
59691
|
const merged = deepMerge4(cur, overlay);
|
|
59488
59692
|
packageFaq = merged.faq;
|
|
59489
59693
|
writeFileSync27(pkgProv, JSON.stringify(merged, null, 2) + "\n");
|
|
@@ -59492,9 +59696,9 @@ async function applyOverlays(input) {
|
|
|
59492
59696
|
writeFileSync27(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
|
|
59493
59697
|
wrote.push(pkgProv);
|
|
59494
59698
|
}
|
|
59495
|
-
const pkgTokens =
|
|
59496
|
-
if (
|
|
59497
|
-
const cur = JSON.parse(
|
|
59699
|
+
const pkgTokens = join62(cwd, "tokens.json");
|
|
59700
|
+
if (existsSync63(pkgTokens) && (tokens.colors || tokens.typography)) {
|
|
59701
|
+
const cur = JSON.parse(readFileSync74(pkgTokens, "utf8"));
|
|
59498
59702
|
let tokensIn = tokens;
|
|
59499
59703
|
if (tokens.typography) {
|
|
59500
59704
|
const fonts = catalogTypography(tokens.typography, cur.typography);
|
|
@@ -59519,9 +59723,9 @@ async function applyOverlays(input) {
|
|
|
59519
59723
|
wrote.push(pkgTokens);
|
|
59520
59724
|
}
|
|
59521
59725
|
const homeAction = homeRefreshActionId(shell);
|
|
59522
|
-
const homeSrc =
|
|
59523
|
-
if (homeAction &&
|
|
59524
|
-
const prev =
|
|
59726
|
+
const homeSrc = join62(cwd, "dev/index.ts");
|
|
59727
|
+
if (homeAction && existsSync63(homeSrc)) {
|
|
59728
|
+
const prev = readFileSync74(homeSrc, "utf8");
|
|
59525
59729
|
const patched = patchBrandParams(prev, overlay, homeAction);
|
|
59526
59730
|
let next = patched.src;
|
|
59527
59731
|
if (!patched.foreign && faq?.length && prev.includes('"tier5.himiBrandedFaq.load"') && !prev.includes('"staticFaq"')) {
|
|
@@ -59552,13 +59756,13 @@ async function applyOverlays(input) {
|
|
|
59552
59756
|
notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
|
|
59553
59757
|
}
|
|
59554
59758
|
}
|
|
59555
|
-
if (!input.iconPath || !
|
|
59759
|
+
if (!input.iconPath || !existsSync63(input.iconPath)) {
|
|
59556
59760
|
const book = input.iconPath ? dirname33(dirname33(resolve45(input.iconPath))) : void 0;
|
|
59557
59761
|
notes.push(
|
|
59558
59762
|
book ? `no icon installed \u2014 ${siteLogoAbsence(book).hint}` : "no icon installed and no business book to say why \u2014 `himi icon generate` draws one from the accent, or `himi icon set <file.png>` installs the customer's own mark"
|
|
59559
59763
|
);
|
|
59560
59764
|
}
|
|
59561
|
-
if (input.iconPath &&
|
|
59765
|
+
if (input.iconPath && existsSync63(input.iconPath)) {
|
|
59562
59766
|
try {
|
|
59563
59767
|
const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
|
|
59564
59768
|
wrote.push(...installed.wrote);
|
|
@@ -63745,7 +63949,7 @@ __export(cli_exports, {
|
|
|
63745
63949
|
runSiteAnalyze: () => runSiteAnalyze,
|
|
63746
63950
|
runSiteFunctionCli: () => runSiteFunctionCli
|
|
63747
63951
|
});
|
|
63748
|
-
import { readFileSync as
|
|
63952
|
+
import { readFileSync as readFileSync75 } from "node:fs";
|
|
63749
63953
|
import { resolve as resolve46 } from "node:path";
|
|
63750
63954
|
function assetFetchFor(_opts) {
|
|
63751
63955
|
return pinnedFetch2;
|
|
@@ -63844,7 +64048,7 @@ async function runSiteFunctionCli(opts) {
|
|
|
63844
64048
|
let source;
|
|
63845
64049
|
if (opts.sourcePath) {
|
|
63846
64050
|
const p = resolve46(opts.cwd ?? process.cwd(), opts.sourcePath);
|
|
63847
|
-
source =
|
|
64051
|
+
source = readFileSync75(p, "utf8");
|
|
63848
64052
|
}
|
|
63849
64053
|
let body;
|
|
63850
64054
|
if (opts.bodyRaw != null) {
|
|
@@ -64103,7 +64307,7 @@ __export(site_create_exports, {
|
|
|
64103
64307
|
runSiteList: () => runSiteList,
|
|
64104
64308
|
writeProvisioningBinding: () => writeProvisioningBinding
|
|
64105
64309
|
});
|
|
64106
|
-
import { existsSync as
|
|
64310
|
+
import { existsSync as existsSync64, readFileSync as readFileSync76, writeFileSync as writeFileSync28 } from "node:fs";
|
|
64107
64311
|
import { resolve as resolvePath2 } from "node:path";
|
|
64108
64312
|
function oauthClientName(projectName) {
|
|
64109
64313
|
return `${projectName} client`;
|
|
@@ -64252,7 +64456,7 @@ async function runSiteCreate(opts) {
|
|
|
64252
64456
|
if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
|
|
64253
64457
|
return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
|
|
64254
64458
|
}
|
|
64255
|
-
function writeProvisioningBinding(target, binding2, fs = { existsSync:
|
|
64459
|
+
function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync64, readFileSync: readFileSync76, writeFileSync: writeFileSync28 }) {
|
|
64256
64460
|
const msid = binding2.siteId;
|
|
64257
64461
|
const path2 = resolvePath2(target);
|
|
64258
64462
|
const committed = committedShellProvisioning(path2);
|
|
@@ -64925,11 +65129,11 @@ var init_context = __esm({
|
|
|
64925
65129
|
});
|
|
64926
65130
|
|
|
64927
65131
|
// src/cli.ts
|
|
64928
|
-
import { mkdtempSync as mkdtempSync4, readFileSync as
|
|
65132
|
+
import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync77, mkdirSync as mkdirSync31, writeFileSync as writeFileSync29, existsSync as existsSync65, rmSync as rmSync14, readdirSync as readdirSync30, statSync as statSync17, lstatSync as lstatSync11, accessSync, constants as constants2, renameSync as renameSync7, cpSync as cpSync3 } from "node:fs";
|
|
64929
65133
|
import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
|
|
64930
65134
|
import { createHash as createHash28, randomUUID as randomUUID5 } from "node:crypto";
|
|
64931
65135
|
import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
|
|
64932
|
-
import { join as
|
|
65136
|
+
import { join as join63, resolve as resolve47, relative as relative12, basename as basename16, dirname as dirname34 } from "node:path";
|
|
64933
65137
|
import { fileURLToPath as fileURLToPath24 } from "node:url";
|
|
64934
65138
|
|
|
64935
65139
|
// ../serve-cli/src/client.ts
|
|
@@ -67045,8 +67249,8 @@ var str6 = (v) => typeof v === "string" ? v : void 0;
|
|
|
67045
67249
|
var num2 = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
|
|
67046
67250
|
function embeddedTemplateCatalog() {
|
|
67047
67251
|
return availableTemplates().map((name) => {
|
|
67048
|
-
const path2 =
|
|
67049
|
-
const meta = JSON.parse(
|
|
67252
|
+
const path2 = join63(templateSourceDir(name), TEMPLATE_META_FILE);
|
|
67253
|
+
const meta = JSON.parse(readFileSync77(path2, "utf8"));
|
|
67050
67254
|
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
67051
67255
|
throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
|
|
67052
67256
|
}
|
|
@@ -67076,7 +67280,9 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
67076
67280
|
scaffold a starter content package (--template <t> starts
|
|
67077
67281
|
from a reference app; --remote fetches it off the serve plane),
|
|
67078
67282
|
with the agent files inside it (AGENTS.md, CLAUDE.md, the himalaya
|
|
67079
|
-
skill, a session-start hook); --no-agent skips them
|
|
67283
|
+
skill, a session-start hook); --no-agent skips them. Also makes
|
|
67284
|
+
the build board (no browser is opened), and its next[] leads with
|
|
67285
|
+
THIS session's steps: the live preview, the first picture, a postcard
|
|
67080
67286
|
himi template list [--remote] list starter templates + metadata (title/description/tags) + each one's start prompt
|
|
67081
67287
|
himi template prompt <name> print the prompt that starts an app from that template
|
|
67082
67288
|
himi template publish [--dir <app>] [--source-dir <dir>] [--name <n>] [--icon <png>] [--visibility public|unlisted]
|
|
@@ -67667,7 +67873,7 @@ WHAT A PATCH DOES NOT CARRY \u2014 all reported in the output, never silent
|
|
|
67667
67873
|
himi docs releasing-with-himi-serve`;
|
|
67668
67874
|
var COMMANDS = [
|
|
67669
67875
|
{ name: "captcha", summary: "create and store native CAPTCHA keys in Serve, or inspect setup status; customer setup verifies Wix site ownership; does not enable member CAPTCHA SDKs", required: "setup|status --app <app> [--content <dir>] [--site <msid>] [--ios-bundle-id <id>] [--android-package-name <id>] [--target <t>]" },
|
|
67670
|
-
{ name: "init", summary: "scaffold a starter content package (OTA-only; no native shells). --template <t> starts from a full reference app (branded-lite = consumer storefront over a Wix site; owner-lite = owner CRUD/management) instead of the minimal counter; --templates lists bundled ones; --remote fetches the template off the serve plane (falls back to the bundled copy offline). The new app also gets its agent files (the same set `himi agent-init` writes: AGENTS.md, CLAUDE.md, the himalaya skill, HIMALAYA.md, a SessionStart hook) so the next session started inside it picks the work up; --no-agent skips them", required: "<name> [--dir] [--template <t>] [--remote] [--no-agent] | --templates" },
|
|
67876
|
+
{ name: "init", summary: "scaffold a starter content package (OTA-only; no native shells). --template <t> starts from a full reference app (branded-lite = consumer storefront over a Wix site; owner-lite = owner CRUD/management) instead of the minimal counter; --templates lists bundled ones; --remote fetches the template off the serve plane (falls back to the bundled copy offline). The new app also gets its agent files (the same set `himi agent-init` writes: AGENTS.md, CLAUDE.md, the himalaya skill, HIMALAYA.md, a SessionStart hook) so the next session started inside it picks the work up; --no-agent skips them. It also makes the build board (.himi/studio/, exactly as `himi studio --no-open` does \u2014 it never opens a browser), so every later render, test, validate, push and progress entry refreshes it; and its `next[]` LEADS with the steps for THIS session \u2014 `himi run --watch &`, the first `himi render <homeScreenId> --png --device iphone`, and that picture's `himi progress` postcard \u2014 ahead of the next-session guidance", required: "<name> [--dir] [--template <t>] [--remote] [--no-agent] | --templates" },
|
|
67671
67877
|
{ name: "template", summary: "starter-template catalog + publishing. Every template is a SHOWCASE APP \u2014 a real published release you can open running before you start from it. `list` prints available templates with metadata (title/description/tags) plus each one's start prompt \u2014 pass --remote to include the serve-plane catalog so an agent can pick one; `prompt <name>` prints just that sentence for one template (the skill URL is the public door, or the plane named by --target/--serve-url); `publish` publishes an app AS a `himi init --template` (needs a himalaya.template.json; builds a previewable release + attaches the scaffold source; --source-dir overrides which tree becomes the source, --name sets the template name; bakes a launcher icon \u2014 --icon <png>, or the committed template-icons/<name>.png \u2014 and extracts accent/palette gallery meta from the scaffold's tokens.json; --visibility unlisted keeps it out of the /v1/templates catalog \u2014 templates default to public); `trim --keep <ids>` cuts an app scaffolded from a template down to those screens (the home, and any screen the navigation pins such as a drawer body, always stays) \u2014 it deletes the other SCREENS/TEMPLATED entries whole, prunes navigation (linkableScreens, tabBar, drawer, deep links, surfaces) and drops tier5-src workers no kept screen uses, then runs validate --strict and rolls everything back if it fails (--force keeps it, --dry-run writes nothing). A kept screen that links to a removed one is refused unless --links follow (keep those too) or --links drop (remove the taps)", required: "list [--remote] | prompt <name> | publish [--dir <app>] [--source-dir <dir>] [--name <n>] [--icon <png>] [--visibility public|unlisted] [--target <t>] | trim --keep <id,id,\u2026> [--content <dir>] [--links follow|drop] [--dry-run] [--force]" },
|
|
67672
67878
|
{ name: "build", summary: "compile tier5-src/<name>/index.ts -> dist/bundles/<name>.bundle.js with esbuild (--binary = resolve published @himalaya/*); semantic TypeScript checking belongs to himi validate", required: "[--content <dir>] [--binary]" },
|
|
67673
67879
|
{ name: "functions", summary: "inspect/invoke server functions and operate durable jobs or schedules", required: "list|describe|openapi|invoke | jobs list|get|cancel|retry|dlq | schedule describe|invoke [--app <a>] [--environment preview|production] [--release <id>]" },
|
|
@@ -67675,8 +67881,8 @@ var COMMANDS = [
|
|
|
67675
67881
|
{ name: "validate", summary: "lint the content package (no push): fixed-contract TypeScript checking for tier5-src workers + schema/proto + token refs + component allowlist + $service bindings + strict-enum foot-guns + capability decls + worker boot dry-run + build/compile failures. Type issues are advisory warnings normally; --strict promotes them and hygiene warnings to errors. Exit 1 on any error. Off-repo, the CLI supplies its compiler and SDK declarations.", required: "[--content <dir>] [--strict]" },
|
|
67676
67882
|
{ name: "test", summary: "DERIVED behavioral crawl \u2014 no test files to write. Boots each screen's real worker, replays its onAppear, then dispatches every action site the descriptor already declares (each from a fresh boot) and checks a narrow set of unambiguous invariants: no uncaught throw, never stuck on `loading`, no `$service:` token or NaN/undefined/[object Object] reaching visible text, no binding aimed at state the worker never defines, no nav param silently dropped, no dead nav target. Catches what validate/render cannot \u2014 a WRONG REDUCER passes both with ok:true. Runs the worker in a DEVICE-PARITY sandbox (no setTimeout/setInterval, as on JSC/WebView) so a bundle that would die on device fails here. Crawls on HERMETIC DATA by default \u2014 zero network: the app's own dev/net-mocks.json first (--net <file> overrides), then the config's CMS `seed:` rows, then a canned fixture of frozen real vertical responses shipped with the CLI (exercises code paths, not API-contract truth) \u2014 so the success/mapping path runs, not just the failure UI. Two boot-only HOSTILE passes (every list empty; every request 500) then check the failure/empty day \u2014 corpus-proven, so their findings are errors. NAV EDGES are followed too: every himi.open site ($item params resolved against row 0 of its list, $service against worker state) and worker _nav directive is harvested, and each baked target is booted WITH the params the source sends \u2014 detail screens finally run their content arm; edge findings are errors tagged edge:<source>. --native runs both real native decoders over the exact baked JSON bytes; --native ios or --native android selects one. It is explicit, runs only from a Himalaya SOURCE CHECKOUT (the decoder oracles are that tree's own HimalayaCore Swift package and Gradle harness, which a published install does not ship), and needs the selected local toolchain. From a source checkout, default runs name missing native verdicts in the coverage ledger; elsewhere the ledger stays silent about them rather than offering a remedy you cannot run. --offline strips all data layers (the old reject-all axis); --no-hostile skips the hostile passes. --record (EXPLICIT, never automatic) refreshes dev/net-mocks.json from live reads first: it boots each screen (load + root onAppear ONLY \u2014 nothing the app's own launch would not fire; the tap/action crawl never sees the live transport, and only proven reads \u2014 GET, or read-shaped POST (/query, /search, /list*, \u2026) \u2014 ever reach the wire), freezes the round-trips, then crawls hermetically on the fresh fixture; record against a QA site, not production. Nodes it cannot judge headless are named, never silently passed. Exit 1 on any error. The CLI carries the authoring runtime off-repo; no per-app SDK install is required. --browser runs the whole loop (build \u2192 extract \u2192 validate \u2192 render \u2192 test) in YOUR browser instead of here, so the source never reaches a pod: it opens one screen's worker + descriptor in a tab, blocks on a loopback callback, and prints the report it posts back. One screen per tab \u2014 name it. --no-open prints the URL rather than launching a browser (SSH); --timeout <ms> bounds the wait, which matters because the page has no execution deadline of its own and an infinite loop in the worker hangs the tab.", required: "[<screenId>\u2026] [--content <dir>] [--net <file>] [--budget <ms>] [--deep [n]] [--record] [--native [ios|android]] [--no-shots] [--offline] [--no-hostile] [--all-screens] [--browser] [--no-open] [--timeout <ms>] [--json]" },
|
|
67677
67883
|
{ name: "ux", summary: "audit or record mobile UX evidence. `audit` checks the public-safe contract, seeded blank acceptance rows, placeholder source copy, app-specific mocks, and iOS/Android audit records. It warns while existing templates migrate; `--strict` promotes missing evidence. `record` stores checks performed on an installed iOS/Android build: `--checks` is required for passed|failed and empty for unavailable, which drove nothing and needs a `--reason` instead. `record` also STAMPS the release it audited (it resolves the id from a build, the same one a push would publish), because an unforced `himi push` of a release with screens refuses when no drive is recorded for THAT release, or when the one that is recorded says `failed` \u2014 the artifact stopped being advice nobody reads (#2955). `unavailable` still satisfies it; only `failed` refuses.", required: "audit [--content <dir>] [--strict] [--json] | record --content <dir> --platform ios|android --status passed|failed|unavailable [--checks back,keyboard,...] [--reason <text>]" },
|
|
67678
|
-
{ 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' },
|
|
67679
|
-
{ name: "studio", summary: "open the BUILD BOARD \u2014 one local page the owner can leave open while an agent builds their app, which fills itself in: every screen as it renders (NEW/CHANGED badges, and each earlier version kept for a filmstrip), the journey stepper and the latest postcard from `himi progress`, the validate/test/UX/draft checks as they run, the site next to the app's home screen with its palette, and the navigation the test crawl followed. Writes .himi/studio/index.html and opens it; the page re-reads its state every two seconds, so nothing needs to be served. OPT-IN BY EXISTENCE: until this command has run, no other command touches .himi/studio/ \u2014 after it, render/test/validate/push/icon/site/ux/progress each refresh the board as they finish (best-effort; never fails a command). Every image is a content-addressed copy in .himi/history/, never a live path into .himi/shots/. Local only, no secrets: it never reads a preview token, handover code or control token. --no-open prints the path instead (SSH, CI). `himi studio reel` writes the MAKING-OF: one self-contained HTML file (every image inlined, nothing fetched) with a flipbook of the home screen version by version, captioned by the postcard in effect at the time, the final screens, and every postcard \u2014 sized to stay attachable, thinning frames first. Defaults to .himi/making-of.html (never archived by push); --out to put it elsewhere.", required: "[--content <dir>] [--no-open] | reel [--out <file>] [--no-open]" },
|
|
67884
|
+
{ name: "progress", summary: 'the build JOURNAL an agent keeps for the owner while it works. `himi progress "<what changed>" --step <1-8|name> --image <png>` appends one postcard to .himi/progress.jsonl \u2014 the step is one of the customer journey\'s eight (discover, classify, plan, implement, brand, validate, review, download) \u2014 and COPIES each image, content-addressed, into .himi/history/, because .himi/shots/ is overwritten by every render and cleared by every full `himi test`, so a path into it would later show a different picture than the one the owner was sent. --image repeats. --notify also raises a best-effort desktop notification for an owner who stepped away. A bare `himi progress` prints the journal with the current step and elapsed time \u2014 also how an agent recovers its place after its context was compacted. APPROVALS: `--approve <gate> "<what>"` records one the customer just gave (gates: site-create, connect, private-data, draft, promote, push-signing, qa-build) in .himi/approvals.jsonl, and `--done <gate>` / `--drop <gate>` closes it \u2014 an approval is owed until then, and the chat that held it does not survive a new session. `--brief` prints plain text for a session start: the current step, the last postcard, every open approval, and whether this app\'s agent files are stale \u2014 the SessionStart hook `himi agent-init` installs runs exactly this. The CLI also journals three milestones by itself \u2014 the first PNG render of the home screen (once per app), every completed `himi test` crawl, every draft push \u2014 marked `"by": "himi"`; they never move the journey step, carry no link or credential, and step aside (folded out of every reader) when the agent journals the same step or picture within five minutes. Local only: nothing is sent anywhere.', required: '["<message>" [--step <1-8|name>] [--image <png>]\u2026 [--notify]] [--content <dir>] | --approve|--done|--drop <gate> ["<note>"] | --brief' },
|
|
67885
|
+
{ name: "studio", summary: "open the BUILD BOARD \u2014 one local page the owner can leave open while an agent builds their app, which fills itself in: every screen as it renders (NEW/CHANGED badges, and each earlier version kept for a filmstrip), the journey stepper and the latest postcard from `himi progress`, the validate/test/UX/draft checks as they run, the site next to the app's home screen with its palette, and the navigation the test crawl followed. Writes .himi/studio/index.html and opens it; the page re-reads its state every two seconds, so nothing needs to be served. OPT-IN BY EXISTENCE: until this command (or `himi init`, which makes the board for every app it creates, without opening a browser) has run, no other command touches .himi/studio/ \u2014 after it, render/test/validate/push/icon/site/ux/progress each refresh the board as they finish (best-effort; never fails a command). Every image is a content-addressed copy in .himi/history/, never a live path into .himi/shots/. Local only, no secrets: it never reads a preview token, handover code or control token. --no-open prints the path instead (SSH, CI). `himi studio reel` writes the MAKING-OF: one self-contained HTML file (every image inlined, nothing fetched) with a flipbook of the home screen version by version, captioned by the postcard in effect at the time, the final screens, and every postcard \u2014 sized to stay attachable, thinning frames first. Defaults to .himi/making-of.html (never archived by push); --out to put it elsewhere.", required: "[--content <dir>] [--no-open] | reel [--out <file>] [--no-open]" },
|
|
67680
67886
|
{ name: "render", summary: "headless-render a screen with the web renderer: render-tree + diagnostics, optional --png [<file>] (bare: .himi/shots/<id>.png, what the build board shows), --scheme dark, --tree. Local by default (content dir). Pass --remote --app --release to hit GET /v1/preview/\u2026/render on the serve plane after a push. Boots the worker so $service bindings resolve; --static raw bindings; --live real Wix fetches; --state injects worker state; --input supplies pre-boot navigation params; --width/--device for PNG viewport; --rtl for dir=rtl + $env:isRTL.", required: "<screenId> [--content <dir>] [--scheme dark] [--png [<file>]] [--tree] [--static] [--live] [--state <json|file>] [--input <json|file>] [--width <px> | --device <name>] [--rtl] [--remote --app --release]" },
|
|
67681
67887
|
{ name: "cms", summary: "inspect, provision, and seed the app's CMS (Wix Data) collections, declared as a `cms` block in config.ts. `query` is READ-ONLY \u2014 by default it fetches ONLY the physical ids `config.ts` declares (item counts + schema drift) and reports `siteScanned: false`; it never lists the site, so an UNDECLARED `himi_<app>_` collection this app owns is not reached without `--all`. `--all` SCANS the site \u2014 every collection it lists is labeled `owned`/`adopted`/`foreign`, and it describes every foreign one \u2014 id, non-system field keys + types, and the site's read role \u2014 so an app with no `cms` block at all can DISCOVER a collection to adopt (`--all` is the one case where a missing `cms` block is not 'nothing to do'). Foreign collections are described up to a cap and are never item-counted (`itemCount: null`), because a row count is one query each; `foreign.count` is how many the scan LISTED \u2014 it follows the list endpoint's pages, and `listingIncomplete: true` says when the walk stopped short of the end, with `unlistedCollections` counting what it left out when Wix gave a paging total \u2014 and `foreign.truncated` says how many of those went undescribed, each still NAMED in `foreign.others` (id + displayName), so a collection the site already has is never hidden behind the cap. The scan is OWNER-scoped \u2014 it needs --site <msid> (or WIX_SITE_ID) plus owner auth via `wix token`; a visitor token can read a public collection's ITEMS but can never enumerate collections, so there is no tokenless discovery path. `create` reconciles declared collections additively and idempotently, and REFUSES any id outside the app's `himi_<app>_` namespace, so it is safe against a production site. It reports declared-vs-site `permissionDrift` but never writes permissions unless asked with --apply-permissions, so a field reconcile can't silently revert access control changed in the dashboard. `seed` inserts the git-tracked `seed:` rows into EMPTY owned collections (--force to add to a non-empty one; --ai writes placeholder rows plus a refinement prompt for you to review). Adopted collections (declared by `wixId`) are read-only and never created, updated, or seeded. Site from --site <msid> or WIX_SITE_ID; owner auth via `wix token`.", required: "query|create|seed [--site <msid>] [--content <dir>] [--all] [--dry-run] [--force] [--allow-destructive] [--apply-permissions] [--only <id>] [--ai] [--count <n>]" },
|
|
67682
67888
|
{ name: "data", summary: "read-only plan or explicitly provision/seed declared KV and Wix Data resources. Preview and production are separate scopes. KV administration uses the operator data plane from --data-url/HIMI_DATA_ADMIN_URL and HIMI_DATA_ADMIN_TOKEN; draft push never calls it.", required: "plan|create|seed [--site <msid>] [--environment preview|production] [--content <dir>] [--data-url <url>] [--dry-run] [--force]" },
|
|
@@ -67725,7 +67931,7 @@ var COMMANDS = [
|
|
|
67725
67931
|
];
|
|
67726
67932
|
function cliVersion() {
|
|
67727
67933
|
try {
|
|
67728
|
-
return JSON.parse(
|
|
67934
|
+
return JSON.parse(readFileSync77(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
|
|
67729
67935
|
} catch {
|
|
67730
67936
|
return "unknown";
|
|
67731
67937
|
}
|
|
@@ -67843,7 +68049,7 @@ function ageInDays(publishedAt, now = Date.now()) {
|
|
|
67843
68049
|
}
|
|
67844
68050
|
function packageVersion(path2) {
|
|
67845
68051
|
try {
|
|
67846
|
-
const version2 = JSON.parse(
|
|
68052
|
+
const version2 = JSON.parse(readFileSync77(path2, "utf8")).version;
|
|
67847
68053
|
return typeof version2 === "string" && version2 ? version2 : void 0;
|
|
67848
68054
|
} catch {
|
|
67849
68055
|
return void 0;
|
|
@@ -67852,7 +68058,7 @@ function packageVersion(path2) {
|
|
|
67852
68058
|
function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
|
|
67853
68059
|
let dir = resolve47(fromDir);
|
|
67854
68060
|
for (; ; ) {
|
|
67855
|
-
const version2 = packageVersion(
|
|
68061
|
+
const version2 = packageVersion(join63(dir, "node_modules", "@wix", "himalaya", "package.json"));
|
|
67856
68062
|
if (version2) return { version: version2, source: "local" };
|
|
67857
68063
|
const parent = dirname34(dir);
|
|
67858
68064
|
if (parent === dir) break;
|
|
@@ -67862,7 +68068,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
|
|
|
67862
68068
|
if (bundled) return { version: bundled, source: "bundled" };
|
|
67863
68069
|
try {
|
|
67864
68070
|
const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
67865
|
-
const version2 = root ? packageVersion(
|
|
68071
|
+
const version2 = root ? packageVersion(join63(root, "@wix", "himalaya", "package.json")) : void 0;
|
|
67866
68072
|
return version2 ? { version: version2, source: "global" } : {};
|
|
67867
68073
|
} catch {
|
|
67868
68074
|
return {};
|
|
@@ -67909,11 +68115,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
|
|
|
67909
68115
|
var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
|
|
67910
68116
|
var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
|
|
67911
68117
|
function updateCachePath(env = process.env) {
|
|
67912
|
-
return env.HIMI_UPDATE_CACHE_FILE ??
|
|
68118
|
+
return env.HIMI_UPDATE_CACHE_FILE ?? join63(homedir7(), ".himalaya", "update-check.json");
|
|
67913
68119
|
}
|
|
67914
68120
|
function readUpdateCache(path2) {
|
|
67915
68121
|
try {
|
|
67916
|
-
const parsed = JSON.parse(
|
|
68122
|
+
const parsed = JSON.parse(readFileSync77(path2, "utf8"));
|
|
67917
68123
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
67918
68124
|
} catch {
|
|
67919
68125
|
return {};
|
|
@@ -67981,12 +68187,12 @@ function createUpdateRunner(spawn7 = spawnSync5) {
|
|
|
67981
68187
|
},
|
|
67982
68188
|
installedVersion: () => {
|
|
67983
68189
|
const root = globalNodeModulesRoot();
|
|
67984
|
-
return root ? packageVersion(
|
|
68190
|
+
return root ? packageVersion(join63(root, "@wix", "himalaya-cli", "package.json")) : void 0;
|
|
67985
68191
|
},
|
|
67986
68192
|
reexec: (argv) => {
|
|
67987
68193
|
const root = globalNodeModulesRoot();
|
|
67988
|
-
const entry = root ?
|
|
67989
|
-
if (!entry || !
|
|
68194
|
+
const entry = root ? join63(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
|
|
68195
|
+
if (!entry || !existsSync65(entry)) return void 0;
|
|
67990
68196
|
const result = spawnSync5(process.execPath, [entry, ...argv], {
|
|
67991
68197
|
// inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
|
|
67992
68198
|
stdio: "inherit",
|
|
@@ -68033,7 +68239,7 @@ function staleUpdateLockFile(cachePath, now) {
|
|
|
68033
68239
|
for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
|
|
68034
68240
|
let content;
|
|
68035
68241
|
try {
|
|
68036
|
-
content =
|
|
68242
|
+
content = readFileSync77(path2, "utf8");
|
|
68037
68243
|
} catch {
|
|
68038
68244
|
continue;
|
|
68039
68245
|
}
|
|
@@ -68056,7 +68262,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
|
|
|
68056
68262
|
const mine = lockStamp(now);
|
|
68057
68263
|
const readLock = (path2) => {
|
|
68058
68264
|
try {
|
|
68059
|
-
return
|
|
68265
|
+
return readFileSync77(path2, "utf8");
|
|
68060
68266
|
} catch {
|
|
68061
68267
|
return void 0;
|
|
68062
68268
|
}
|
|
@@ -68640,7 +68846,7 @@ function executableOnPath(name, env = process.env) {
|
|
|
68640
68846
|
const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
68641
68847
|
for (const dir of entries) {
|
|
68642
68848
|
for (const suffix of suffixes) {
|
|
68643
|
-
const candidate =
|
|
68849
|
+
const candidate = join63(dir, `${name}${suffix}`);
|
|
68644
68850
|
try {
|
|
68645
68851
|
if (!statSync17(candidate).isFile()) continue;
|
|
68646
68852
|
if (process.platform !== "win32") accessSync(candidate, constants2.X_OK);
|
|
@@ -68749,7 +68955,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
68749
68955
|
const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths2(), paths_exports));
|
|
68750
68956
|
const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
|
|
68751
68957
|
const iosYmlPath = iosProjectYml2(app);
|
|
68752
|
-
const iosYml =
|
|
68958
|
+
const iosYml = existsSync65(iosYmlPath) ? readFileSync77(iosYmlPath, "utf8") : "";
|
|
68753
68959
|
let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
|
|
68754
68960
|
if (!optedIn) {
|
|
68755
68961
|
const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
|
|
@@ -68763,7 +68969,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
68763
68969
|
}
|
|
68764
68970
|
function readConfigSource(dir) {
|
|
68765
68971
|
try {
|
|
68766
|
-
return
|
|
68972
|
+
return readFileSync77(join63(dir, "config.ts"), "utf8");
|
|
68767
68973
|
} catch {
|
|
68768
68974
|
return null;
|
|
68769
68975
|
}
|
|
@@ -68799,7 +69005,7 @@ function keptPlan(kept) {
|
|
|
68799
69005
|
}
|
|
68800
69006
|
async function initFromRemoteTemplate(name, parentDir, template, c) {
|
|
68801
69007
|
const dir = resolve47(parentDir, name);
|
|
68802
|
-
if (
|
|
69008
|
+
if (existsSync65(join63(dir, "himalaya.content.json"))) {
|
|
68803
69009
|
throw new Error(`content package already exists at ${dir}`);
|
|
68804
69010
|
}
|
|
68805
69011
|
const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
|
|
@@ -68842,7 +69048,7 @@ function symlinkDestinationIssue(dest) {
|
|
|
68842
69048
|
function restoreDestinationIssue(dest, force) {
|
|
68843
69049
|
const link = symlinkDestinationIssue(dest);
|
|
68844
69050
|
if (link) return link;
|
|
68845
|
-
if (!
|
|
69051
|
+
if (!existsSync65(dest)) return null;
|
|
68846
69052
|
if (!statSync17(dest).isDirectory()) {
|
|
68847
69053
|
return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
|
|
68848
69054
|
}
|
|
@@ -68857,7 +69063,7 @@ function restoreDestinationIssue(dest, force) {
|
|
|
68857
69063
|
function isHimalayaMonorepoCheckout(start) {
|
|
68858
69064
|
let dir = resolve47(start);
|
|
68859
69065
|
for (; ; ) {
|
|
68860
|
-
if (
|
|
69066
|
+
if (existsSync65(join63(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync65(join63(dir, "core", "serve", "src", "server.ts"))) return true;
|
|
68861
69067
|
const parent = dirname34(dir);
|
|
68862
69068
|
if (parent === dir) return false;
|
|
68863
69069
|
dir = parent;
|
|
@@ -68895,7 +69101,7 @@ function shellShaDivergenceWarnings(jobs) {
|
|
|
68895
69101
|
}
|
|
68896
69102
|
async function templatePublishName(sourceDir) {
|
|
68897
69103
|
const id = await appId(sourceDir);
|
|
68898
|
-
return IDENTITY_SENTINELS.some((s) => id.includes(s)) ?
|
|
69104
|
+
return IDENTITY_SENTINELS.some((s) => id.includes(s)) ? basename16(sourceDir) : id;
|
|
68899
69105
|
}
|
|
68900
69106
|
function templateNameError(name, from) {
|
|
68901
69107
|
if (name.startsWith(TEMPLATE_APP_PREFIX)) {
|
|
@@ -68918,7 +69124,7 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68918
69124
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
68919
69125
|
);
|
|
68920
69126
|
const repoRoot2 = resolve47(fileURLToPath24(new URL("../../..", import.meta.url)));
|
|
68921
|
-
const root =
|
|
69127
|
+
const root = join63(repoRoot2, "node_modules", ".cache", "himi-template-preview");
|
|
68922
69128
|
const stillRunning = (pid) => {
|
|
68923
69129
|
try {
|
|
68924
69130
|
process.kill(pid, 0);
|
|
@@ -68932,12 +69138,12 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68932
69138
|
if (!entry.isDirectory()) continue;
|
|
68933
69139
|
const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
|
|
68934
69140
|
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
|
|
68935
|
-
rmSync14(
|
|
69141
|
+
rmSync14(join63(root, entry.name), { recursive: true, force: true });
|
|
68936
69142
|
}
|
|
68937
69143
|
}
|
|
68938
69144
|
} catch {
|
|
68939
69145
|
}
|
|
68940
|
-
const dest =
|
|
69146
|
+
const dest = join63(root, `${slug}-${process.pid}`);
|
|
68941
69147
|
rmSync14(dest, { recursive: true, force: true });
|
|
68942
69148
|
mkdirSync31(dest, { recursive: true });
|
|
68943
69149
|
try {
|
|
@@ -68950,17 +69156,17 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68950
69156
|
}
|
|
68951
69157
|
async function appId(dir) {
|
|
68952
69158
|
try {
|
|
68953
|
-
const { readFileSync:
|
|
68954
|
-
const m = JSON.parse(
|
|
69159
|
+
const { readFileSync: readFileSync78 } = await import("node:fs");
|
|
69160
|
+
const m = JSON.parse(readFileSync78(join63(dir, "himalaya.content.json"), "utf8"));
|
|
68955
69161
|
if (m.name) return m.name;
|
|
68956
69162
|
} catch {
|
|
68957
69163
|
}
|
|
68958
|
-
return
|
|
69164
|
+
return basename16(dir);
|
|
68959
69165
|
}
|
|
68960
69166
|
async function contentVisibility(dir) {
|
|
68961
69167
|
try {
|
|
68962
|
-
const { readFileSync:
|
|
68963
|
-
const m = JSON.parse(
|
|
69168
|
+
const { readFileSync: readFileSync78 } = await import("node:fs");
|
|
69169
|
+
const m = JSON.parse(readFileSync78(join63(dir, "himalaya.content.json"), "utf8"));
|
|
68964
69170
|
if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
|
|
68965
69171
|
} catch {
|
|
68966
69172
|
}
|
|
@@ -69184,7 +69390,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
|
|
|
69184
69390
|
...res.removed.length ? { removed: res.removed, note: "older copies at the app root, moved to .himi/legacy-agent-files/ (a backup, in case one became app code) \u2014 the current ones live in .agents/skills/himalaya/" } : {},
|
|
69185
69391
|
// In a git repo the refresh moves the diff identity an earlier `himi test` attested (that
|
|
69186
69392
|
// hash is shared with the repo gates and deliberately exempts nothing but its own metadata).
|
|
69187
|
-
...
|
|
69393
|
+
...existsSync65(join63(dir, ".himi", "attestations", "latest.json")) ? { next: "if `himi push` then refuses the attestation as stale, re-run `himi test` \u2014 in a git checkout this refresh changed the tree it covered" } : {},
|
|
69188
69394
|
...res.skipped.length ? { skipped: res.skipped } : {},
|
|
69189
69395
|
portalUrl: idx.portalUrl
|
|
69190
69396
|
});
|
|
@@ -69207,7 +69413,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
|
|
|
69207
69413
|
try {
|
|
69208
69414
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69209
69415
|
const bres = await buildContentForValidation2(dir, { resolution });
|
|
69210
|
-
out = mkdtempSync4(
|
|
69416
|
+
out = mkdtempSync4(join63(tmpdir5(), "himi-ux-record-"));
|
|
69211
69417
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
69212
69418
|
const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
|
|
69213
69419
|
const releaseId = outcome.manifest.releaseId;
|
|
@@ -69257,8 +69463,8 @@ function uxRestoreCommands(ctx) {
|
|
|
69257
69463
|
};
|
|
69258
69464
|
}
|
|
69259
69465
|
function uxHandoverHint(uxEvidence, ctx) {
|
|
69260
|
-
const { releaseId, contentArg, door, app } = ctx;
|
|
69261
|
-
const uxRemedy = uxRecordCommands(
|
|
69466
|
+
const { releaseId, contentArg: contentArg2, door, app } = ctx;
|
|
69467
|
+
const uxRemedy = uxRecordCommands(contentArg2);
|
|
69262
69468
|
if (uxEvidence.state === "inherited-screens") {
|
|
69263
69469
|
const restore = uxRestoreCommands(ctx);
|
|
69264
69470
|
const alsoOwed = uxEvidence.supersededState === "failed" ? ` This package's own drive FAILED on ${uxEvidence.failedPlatforms.join(", ")}, so you owe more than a record: fix what that drive found, then record it against the restored tree \u2014 re-recording a failure without changing the app writes the same failure down again.` : uxEvidence.supersededState ? ` This package also has no drive this gate accepts (${uxEvidence.supersededState}), so the record below is a step you take AFTER the restore, not instead of it.` : "";
|
|
@@ -69385,7 +69591,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
69385
69591
|
let js;
|
|
69386
69592
|
for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
|
|
69387
69593
|
try {
|
|
69388
|
-
js =
|
|
69594
|
+
js = readFileSync77(join63(outDir, candidate), "utf8");
|
|
69389
69595
|
break;
|
|
69390
69596
|
} catch {
|
|
69391
69597
|
}
|
|
@@ -69416,7 +69622,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
69416
69622
|
}
|
|
69417
69623
|
return { families, source: "dist/bundles" };
|
|
69418
69624
|
}
|
|
69419
|
-
var boardOpen = (dir) =>
|
|
69625
|
+
var boardOpen = (dir) => existsSync65(join63(dir, ".himi", "studio", "index.html"));
|
|
69420
69626
|
var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
|
|
69421
69627
|
async function leaveForBoard(dir, record2, value) {
|
|
69422
69628
|
if (!boardOpen(dir)) return;
|
|
@@ -69711,12 +69917,18 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69711
69917
|
const owed = openApprovals2(readApprovals2(dir).events).length;
|
|
69712
69918
|
next.push(`carried the planning journal into the app (${carried.join(", ")}${owed ? `; ${owed} approval${owed === 1 ? "" : "s"} still owed` : ""}) \u2014 \`himi progress --brief\` there shows it`);
|
|
69713
69919
|
}
|
|
69714
|
-
const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f) =>
|
|
69920
|
+
const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f) => existsSync65(join63(parentDir, f)));
|
|
69715
69921
|
if (planInParent.length) {
|
|
69716
69922
|
next.push(`${planInParent.join(" and ")} in ${parentDir} ${planInParent.length > 1 ? "are" : "is"} not the app's \u2014 if that is the approved plan, move it over the template's boilerplate in ${dir}`);
|
|
69717
69923
|
}
|
|
69718
69924
|
return { ...seeded, next };
|
|
69719
69925
|
};
|
|
69926
|
+
const startSession = async (dir, agent2) => {
|
|
69927
|
+
const { openBoardForSession: openBoardForSession2, sessionSteps: sessionSteps2, homeScreenIdOf: homeScreenIdOf2 } = await Promise.resolve().then(() => (init_milestones(), milestones_exports));
|
|
69928
|
+
const board = await openBoardForSession2(dir);
|
|
69929
|
+
const { next: later2, ...rest } = agent2;
|
|
69930
|
+
return { ...rest, board, next: [...sessionSteps2({ dir, home: homeScreenIdOf2(dir) }), ...later2 ?? []] };
|
|
69931
|
+
};
|
|
69720
69932
|
if (template && flags.remote === true) {
|
|
69721
69933
|
let fetched;
|
|
69722
69934
|
try {
|
|
@@ -69729,14 +69941,14 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69729
69941
|
io.error(JSON.stringify({ warning: `remote template fetch failed (${e.message}); falling back to the bundled "${template}"` }));
|
|
69730
69942
|
}
|
|
69731
69943
|
if (fetched) {
|
|
69732
|
-
const agent2 = await withAgentFiles(fetched.dir);
|
|
69944
|
+
const agent2 = await startSession(fetched.dir, await withAgentFiles(fetched.dir));
|
|
69733
69945
|
const pushSetup2 = await offerPushSetup2({ contentDir: fetched.dir, flags, io });
|
|
69734
69946
|
print({ ok: true, app: name, dir: fetched.dir, template, source: "remote", files: fetched.files, ...keptPlan(fetched.kept), ...agent2, pushSetup: pushSetup2 });
|
|
69735
69947
|
return 0;
|
|
69736
69948
|
}
|
|
69737
69949
|
}
|
|
69738
69950
|
const res = scaffoldContentPackage(name, parentDir, template);
|
|
69739
|
-
const agent = await withAgentFiles(res.dir);
|
|
69951
|
+
const agent = await startSession(res.dir, await withAgentFiles(res.dir));
|
|
69740
69952
|
const pushSetup = await offerPushSetup2({ contentDir: res.dir, flags, io });
|
|
69741
69953
|
print({ ok: true, app: name, dir: res.dir, ...template ? { template, source: "embedded" } : {}, files: res.files, ...keptPlan(res.kept), ...agent, pushSetup });
|
|
69742
69954
|
return 0;
|
|
@@ -69838,7 +70050,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69838
70050
|
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
69839
70051
|
let meta;
|
|
69840
70052
|
try {
|
|
69841
|
-
meta = JSON.parse(
|
|
70053
|
+
meta = JSON.parse(readFileSync77(join63(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
69842
70054
|
} catch {
|
|
69843
70055
|
io.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
|
|
69844
70056
|
return 2;
|
|
@@ -69848,7 +70060,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69848
70060
|
return 2;
|
|
69849
70061
|
}
|
|
69850
70062
|
try {
|
|
69851
|
-
const appearance = extractTemplateAppearance(JSON.parse(
|
|
70063
|
+
const appearance = extractTemplateAppearance(JSON.parse(readFileSync77(join63(sourceDir, "tokens.json"), "utf8")));
|
|
69852
70064
|
meta = { ...appearance, ...meta };
|
|
69853
70065
|
} catch {
|
|
69854
70066
|
}
|
|
@@ -69870,7 +70082,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69870
70082
|
const force = flags.force === true;
|
|
69871
70083
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69872
70084
|
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
69873
|
-
const out = mkdtempSync4(
|
|
70085
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-template-"));
|
|
69874
70086
|
publishScratch.push(out);
|
|
69875
70087
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
69876
70088
|
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
@@ -69924,7 +70136,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69924
70136
|
let iconHash;
|
|
69925
70137
|
if (iconPath) {
|
|
69926
70138
|
try {
|
|
69927
|
-
const bytes2 =
|
|
70139
|
+
const bytes2 = readFileSync77(iconPath);
|
|
69928
70140
|
payload.icon = bytes2.toString("base64");
|
|
69929
70141
|
iconHash = createHash28("sha256").update(bytes2).digest("hex");
|
|
69930
70142
|
} catch {
|
|
@@ -70167,7 +70379,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70167
70379
|
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
70168
70380
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
70169
70381
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
70170
|
-
const out = mkdtempSync4(
|
|
70382
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-validate-"));
|
|
70171
70383
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
70172
70384
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
70173
70385
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -70210,7 +70422,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70210
70422
|
const path2 = dpxSessionTokenPath();
|
|
70211
70423
|
let raw;
|
|
70212
70424
|
try {
|
|
70213
|
-
raw =
|
|
70425
|
+
raw = readFileSync77(path2, "utf8");
|
|
70214
70426
|
} catch {
|
|
70215
70427
|
throw new Error(`no DPX BO session at ${path2}; run dpx auth login, write dpx auth token to that path, then himi login --dpx --target bo`);
|
|
70216
70428
|
}
|
|
@@ -70330,13 +70542,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70330
70542
|
case "studio": {
|
|
70331
70543
|
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
70332
70544
|
const dir = contentDir(flags);
|
|
70333
|
-
if (!
|
|
70545
|
+
if (!existsSync65(join63(dir, "himalaya.content.json"))) {
|
|
70334
70546
|
io.error(JSON.stringify({ ok: false, error: "not_a_content_package", dir, hint: "run from the app directory (or pass --content <dir>) \u2014 the board reads that package's .himi/" }));
|
|
70335
70547
|
return 2;
|
|
70336
70548
|
}
|
|
70337
70549
|
if (pos[1] === "reel") {
|
|
70338
70550
|
const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
|
|
70339
|
-
const out = resolve47(str6(flags.out) ??
|
|
70551
|
+
const out = resolve47(str6(flags.out) ?? join63(dir, ".himi", "making-of.html"));
|
|
70340
70552
|
const { html, plan } = buildReel2(dir);
|
|
70341
70553
|
mkdirSync31(dirname34(out), { recursive: true });
|
|
70342
70554
|
writeFileSync29(out, html);
|
|
@@ -70402,8 +70614,8 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70402
70614
|
formatBrief: formatBrief2
|
|
70403
70615
|
} = await Promise.resolve().then(() => (init_progress(), progress_exports));
|
|
70404
70616
|
const dir = contentDir(flags);
|
|
70405
|
-
const
|
|
70406
|
-
const isContentPackage =
|
|
70617
|
+
const journal2 = journalPath2(dir);
|
|
70618
|
+
const isContentPackage = existsSync65(join63(dir, "himalaya.content.json"));
|
|
70407
70619
|
const hint = isContentPackage ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
|
|
70408
70620
|
const message = pos.slice(1).join(" ").trim();
|
|
70409
70621
|
const approvalFlags = ["approve", "done", "drop"].filter((f) => flags[f] !== void 0);
|
|
@@ -70455,7 +70667,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70455
70667
|
}
|
|
70456
70668
|
const { entries, skipped } = readProgress2(dir);
|
|
70457
70669
|
const approvals = openApprovals2(readApprovals2(dir).events);
|
|
70458
|
-
print({ ok: true, journal, ...summarizeProgress2(entries), entries, ...approvals.length ? { approvals } : {}, ...skipped ? { skipped } : {}, ...hint });
|
|
70670
|
+
print({ ok: true, journal: journal2, ...summarizeProgress2(entries), entries, ...approvals.length ? { approvals } : {}, ...skipped ? { skipped } : {}, ...hint });
|
|
70459
70671
|
return 0;
|
|
70460
70672
|
}
|
|
70461
70673
|
let step;
|
|
@@ -70476,7 +70688,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70476
70688
|
const entry = appendProgress2(dir, { message, ...step ? { step } : {}, images });
|
|
70477
70689
|
const notified = flags.notify === true ? await notifyDesktop2(`himi \xB7 ${appLabel2(dir) ?? "your app"}`, message) : void 0;
|
|
70478
70690
|
const { count: count2 } = summarizeProgress2(readProgress2(dir).entries);
|
|
70479
|
-
print({ ok: true, entry, journal, count: count2, ...notified === void 0 ? {} : { notified }, ...hint });
|
|
70691
|
+
print({ ok: true, entry, journal: journal2, count: count2, ...notified === void 0 ? {} : { notified }, ...hint });
|
|
70480
70692
|
return 0;
|
|
70481
70693
|
} catch (e) {
|
|
70482
70694
|
if (e instanceof ProgressError2) {
|
|
@@ -70539,7 +70751,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70539
70751
|
case "test": {
|
|
70540
70752
|
const dir = contentDir(flags);
|
|
70541
70753
|
const structuredOutput = flags.json === true || io.isTTY !== true;
|
|
70542
|
-
if (
|
|
70754
|
+
if (existsSync65(join63(dir, "functions"))) {
|
|
70543
70755
|
const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
|
|
70544
70756
|
const loaded = await loadFunctionsApp2(dir);
|
|
70545
70757
|
const results = [];
|
|
@@ -70626,7 +70838,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70626
70838
|
}
|
|
70627
70839
|
}
|
|
70628
70840
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
70629
|
-
const out = mkdtempSync4(
|
|
70841
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-test-"));
|
|
70630
70842
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
70631
70843
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
70632
70844
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -70671,7 +70883,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70671
70883
|
io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
|
|
70672
70884
|
return 2;
|
|
70673
70885
|
}
|
|
70674
|
-
const sources = collectWorkerSources2(
|
|
70886
|
+
const sources = collectWorkerSources2(join63(dir, "tier5-src"), screen.bundleName);
|
|
70675
70887
|
if (!sources) {
|
|
70676
70888
|
io.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
|
|
70677
70889
|
return 2;
|
|
@@ -70836,7 +71048,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70836
71048
|
const sp = await runShotsPass2({
|
|
70837
71049
|
descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
|
|
70838
71050
|
tokens: outcome.tokens,
|
|
70839
|
-
outDir:
|
|
71051
|
+
outDir: join63(dir, ".himi", "shots"),
|
|
70840
71052
|
width: 390,
|
|
70841
71053
|
layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
|
|
70842
71054
|
...budgetMs ? { budgetMs } : {},
|
|
@@ -70874,7 +71086,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70874
71086
|
releaseId: result.releaseId,
|
|
70875
71087
|
releasePayload: release,
|
|
70876
71088
|
descriptors: attestedDescriptors,
|
|
70877
|
-
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""),
|
|
71089
|
+
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join63(dir, ".himi", "shots", name)])),
|
|
70878
71090
|
coverage: {
|
|
70879
71091
|
screens: crawledScreens.size,
|
|
70880
71092
|
actionsDispatched: result.actions.exercised,
|
|
@@ -70886,14 +71098,30 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70886
71098
|
counts: { errors: result.counts.errors, warnings: result.counts.warnings, gaps: ledger.length }
|
|
70887
71099
|
}
|
|
70888
71100
|
});
|
|
71101
|
+
const home = outcome.homeScreenId;
|
|
71102
|
+
const { afterTestRun: afterTestRun2 } = await Promise.resolve().then(() => (init_milestones(), milestones_exports));
|
|
71103
|
+
const afterRun = afterTestRun2(dir, {
|
|
71104
|
+
runId: attestation.runId,
|
|
71105
|
+
screens: crawledScreens.size,
|
|
71106
|
+
actions: result.actions.exercised,
|
|
71107
|
+
errors: result.counts.errors,
|
|
71108
|
+
...result.navGraph ? { broken: result.navGraph.broken.length, unreached: result.navGraph.unreached.length } : {},
|
|
71109
|
+
...home && writtenShots.includes(`${home}.png`) ? { homeShot: join63(dir, ".himi", "shots", `${home}.png`) } : {},
|
|
71110
|
+
boardOpen: boardOpen(dir)
|
|
71111
|
+
});
|
|
70889
71112
|
if (structuredOutput) {
|
|
70890
|
-
print(
|
|
70891
|
-
|
|
70892
|
-
|
|
70893
|
-
|
|
70894
|
-
|
|
70895
|
-
|
|
70896
|
-
|
|
71113
|
+
print({
|
|
71114
|
+
...foldLegacyReport(legacy, {
|
|
71115
|
+
source: "test",
|
|
71116
|
+
evidence: { runId: attestation.runId, ts: attestation.runId.slice(0, 24), gitDiffHash },
|
|
71117
|
+
gaps: ledger,
|
|
71118
|
+
artifacts: result.shots?.dir ? [{ kind: "shots-dir", path: result.shots.dir }] : []
|
|
71119
|
+
}),
|
|
71120
|
+
...afterRun.postcard ? { postcard: afterRun.postcard } : {},
|
|
71121
|
+
next: afterRun.next
|
|
71122
|
+
});
|
|
71123
|
+
} else io.log(formatReport2(result) + formatDelta2(delta) + formatLedger2(ledger, trend) + `
|
|
71124
|
+
${afterRun.next.join("\n")}`);
|
|
70897
71125
|
await leaveForBoard(dir, "edges", result.edges ?? []);
|
|
70898
71126
|
if (result.navGraph) await leaveForBoard(dir, "map", result.navGraph);
|
|
70899
71127
|
return result.ok ? 0 : 1;
|
|
@@ -70965,7 +71193,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70965
71193
|
return 2;
|
|
70966
71194
|
}
|
|
70967
71195
|
try {
|
|
70968
|
-
const raw = stateArg.trim().startsWith("{") ? stateArg :
|
|
71196
|
+
const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync77(stateArg.replace(/^@/, ""), "utf8");
|
|
70969
71197
|
injectedState = JSON.parse(raw);
|
|
70970
71198
|
} catch (e) {
|
|
70971
71199
|
io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
|
|
@@ -70980,7 +71208,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70980
71208
|
return 2;
|
|
70981
71209
|
}
|
|
70982
71210
|
try {
|
|
70983
|
-
const raw = inputArg.trim().startsWith("{") ? inputArg :
|
|
71211
|
+
const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync77(inputArg.replace(/^@/, ""), "utf8");
|
|
70984
71212
|
const parsed = JSON.parse(raw);
|
|
70985
71213
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
|
|
70986
71214
|
injectedInput = parsed;
|
|
@@ -71029,7 +71257,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71029
71257
|
}
|
|
71030
71258
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
71031
71259
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
71032
|
-
const out = mkdtempSync4(
|
|
71260
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-render-"));
|
|
71033
71261
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
71034
71262
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
71035
71263
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -71043,7 +71271,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71043
71271
|
const diagnostics = (outcome.lint ?? []).find((s) => s.screenId === screenId)?.issues ?? [];
|
|
71044
71272
|
let pngFile;
|
|
71045
71273
|
let attestationPngFile;
|
|
71046
|
-
const shotPath =
|
|
71274
|
+
const shotPath = join63(dir, ".himi", "shots", `${screenId}.png`);
|
|
71047
71275
|
const pngTarget = typeof flags.png === "string" ? str6(flags.png) : flags.png === true ? shotPath : void 0;
|
|
71048
71276
|
if (pngTarget && r.pngBase64) {
|
|
71049
71277
|
pngFile = writePngFile(pngTarget, r.pngBase64);
|
|
@@ -71111,15 +71339,20 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71111
71339
|
coverage: { screens: 1, actionsDispatched: 0, uncoveredFns: 0, gaps: provisional.counts.gaps },
|
|
71112
71340
|
report: { ok: provisional.ok, counts: provisional.counts }
|
|
71113
71341
|
});
|
|
71114
|
-
|
|
71115
|
-
|
|
71116
|
-
|
|
71117
|
-
|
|
71118
|
-
|
|
71119
|
-
|
|
71120
|
-
|
|
71121
|
-
|
|
71122
|
-
|
|
71342
|
+
const afterPng = pngFile ? (await Promise.resolve().then(() => (init_milestones(), milestones_exports))).afterRenderPng(dir, { screenId, homeScreenId: outcome.homeScreenId ?? null, pngFile, renderable: r.renderable, content: str6(flags.content) }) : null;
|
|
71343
|
+
print({
|
|
71344
|
+
...foldLegacyReport(legacyRender, {
|
|
71345
|
+
source: "render",
|
|
71346
|
+
app,
|
|
71347
|
+
screenId,
|
|
71348
|
+
releaseId: outcome.manifest.releaseId,
|
|
71349
|
+
findings: diagnostics,
|
|
71350
|
+
evidence: { runId: attestation.runId, ts: attestation.runId.slice(0, 24), gitDiffHash },
|
|
71351
|
+
artifacts: pngFile ? [{ kind: "png", path: pngFile }] : []
|
|
71352
|
+
}),
|
|
71353
|
+
...afterPng?.postcard ? { postcard: afterPng.postcard } : {},
|
|
71354
|
+
...afterPng?.next.length ? { next: afterPng.next } : {}
|
|
71355
|
+
});
|
|
71123
71356
|
return r.renderable ? 0 : 1;
|
|
71124
71357
|
}
|
|
71125
71358
|
case "tokens": {
|
|
@@ -71379,7 +71612,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71379
71612
|
io.error(JSON.stringify(linked));
|
|
71380
71613
|
return 1;
|
|
71381
71614
|
}
|
|
71382
|
-
if (
|
|
71615
|
+
if (existsSync65(dest)) {
|
|
71383
71616
|
if (!statSync17(dest).isDirectory()) {
|
|
71384
71617
|
io.error(JSON.stringify({
|
|
71385
71618
|
error: `${dest} exists and is not a directory`,
|
|
@@ -71392,7 +71625,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71392
71625
|
io.error(JSON.stringify({ error: `${dest} already exists and is not empty`, hint: "pass --force to write into it anyway (merging, and naming what it keeps), --replace to restore exactly what was archived, or --out/--name to land somewhere else" }));
|
|
71393
71626
|
return 1;
|
|
71394
71627
|
}
|
|
71395
|
-
if (replace && occupied && !
|
|
71628
|
+
if (replace && occupied && !existsSync65(join63(dest, "himalaya.content.json"))) {
|
|
71396
71629
|
io.error(JSON.stringify({
|
|
71397
71630
|
error: `${dest} is not a content package \u2014 refusing to --replace it`,
|
|
71398
71631
|
hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
|
|
@@ -71533,7 +71766,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71533
71766
|
const force = flags.force === true;
|
|
71534
71767
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
71535
71768
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
71536
|
-
const out = mkdtempSync4(
|
|
71769
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-push-"));
|
|
71537
71770
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
71538
71771
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
71539
71772
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -71559,8 +71792,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71559
71792
|
const manifest = outcome.manifest;
|
|
71560
71793
|
const payload = await loadReleaseFromDir(declared, out);
|
|
71561
71794
|
const { shellQuote: shellQuote2 } = await Promise.resolve().then(() => (init_shell_quote(), shell_quote_exports));
|
|
71562
|
-
const contentRel =
|
|
71563
|
-
const
|
|
71795
|
+
const contentRel = relative12(process.cwd(), dir) || ".";
|
|
71796
|
+
const contentArg2 = shellQuote2(contentRel);
|
|
71564
71797
|
if (onlyRaw !== void 0) {
|
|
71565
71798
|
const onlyDraft = flags.draft === true;
|
|
71566
71799
|
const { parseOnlySelectors: parseOnlySelectors2, planFromPayload: planFromPayload2, notCarriedDiff: notCarriedDiff2 } = await Promise.resolve().then(() => (init_release_patch2(), release_patch_exports));
|
|
@@ -71604,7 +71837,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71604
71837
|
});
|
|
71605
71838
|
const patchUxContext = {
|
|
71606
71839
|
releaseId: manifest.releaseId,
|
|
71607
|
-
contentArg,
|
|
71840
|
+
contentArg: contentArg2,
|
|
71608
71841
|
contentDir: contentRel,
|
|
71609
71842
|
app,
|
|
71610
71843
|
door: echoedInvocation("himi push", flags, shellQuote2),
|
|
@@ -71699,7 +71932,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71699
71932
|
const staleEvidence = evidence.staleRuns > 0 ? `${evidence.staleRuns} retained attestation(s) were recorded at this commit, but none describes the content being published` : null;
|
|
71700
71933
|
const attestationErrors = [...evidence.historyErrors, ...staleEvidence ? [staleEvidence] : []];
|
|
71701
71934
|
if (attestationErrors.length > 0 && !force) {
|
|
71702
|
-
const remedy = `\`himi test --content ${
|
|
71935
|
+
const remedy = `\`himi test --content ${contentArg2}\` (or \`himi render <screenId> --content ${contentArg2}\`)`;
|
|
71703
71936
|
const corrupted = evidence.historyErrors.length > 0;
|
|
71704
71937
|
print({
|
|
71705
71938
|
ok: false,
|
|
@@ -71737,7 +71970,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71737
71970
|
// fixing one door and not the other is the drift the shared helpers exist to stop.
|
|
71738
71971
|
hint: uxHandoverHint(uxEvidence, {
|
|
71739
71972
|
releaseId: manifest.releaseId,
|
|
71740
|
-
contentArg,
|
|
71973
|
+
contentArg: contentArg2,
|
|
71741
71974
|
contentDir: contentRel,
|
|
71742
71975
|
app,
|
|
71743
71976
|
door: echoedInvocation("himi push", flags, shellQuote2),
|
|
@@ -71846,11 +72079,13 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71846
72079
|
const base = serveBase();
|
|
71847
72080
|
const explicitTarget = contextualDefaultTarget !== void 0 || flags.target !== void 0 || flags["serve-url"] !== void 0 || !!process.env.HIMI_SERVE_TARGET;
|
|
71848
72081
|
const loopbackWarning = base ? loopbackTargetWarning(base, explicitTarget) : null;
|
|
72082
|
+
const afterDraft = draft ? (await Promise.resolve().then(() => (init_milestones(), milestones_exports))).afterDraftPush(dir, { app, releaseId: release, content: str6(flags.content) }) : null;
|
|
71849
72083
|
print({
|
|
71850
72084
|
ok: true,
|
|
71851
72085
|
app,
|
|
71852
72086
|
releaseId: release,
|
|
71853
72087
|
draft,
|
|
72088
|
+
...afterDraft?.postcard ? { postcard: afterDraft.postcard } : {},
|
|
71854
72089
|
// Say so when the push acquired the slug on the caller's behalf. A claim takes a name
|
|
71855
72090
|
// out of a global first-come namespace, counts against quota, and cannot be undone —
|
|
71856
72091
|
// so it must never happen silently.
|
|
@@ -71891,7 +72126,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71891
72126
|
// behind that: the plane keeps the previous attestation for this release id when a
|
|
71892
72127
|
// push carries none, so the published release can look attested by an earlier run.
|
|
71893
72128
|
...!attestation && staleEvidence ? {
|
|
71894
|
-
attestationNote: `${staleEvidence} \u2014 this release was published with no headless evidence of its own, and the serve plane may still show the attestation from an earlier push of this release id. Re-attest with \`himi test --content ${
|
|
72129
|
+
attestationNote: `${staleEvidence} \u2014 this release was published with no headless evidence of its own, and the serve plane may still show the attestation from an earlier push of this release id. Re-attest with \`himi test --content ${contentArg2}\` and push again to attach one.`
|
|
71895
72130
|
} : {},
|
|
71896
72131
|
// #2955 — the SAME honesty for the UX gate: `--force` published this preview without a
|
|
71897
72132
|
// recorded mobile-UX drive for it, and the link below goes to a customer. Say it in the
|
|
@@ -71899,7 +72134,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71899
72134
|
// the same silence one step apart.
|
|
71900
72135
|
...uxHandoverOverride(uxEvidence, {
|
|
71901
72136
|
releaseId: manifest.releaseId,
|
|
71902
|
-
contentArg,
|
|
72137
|
+
contentArg: contentArg2,
|
|
71903
72138
|
contentDir: contentRel,
|
|
71904
72139
|
app,
|
|
71905
72140
|
door: echoedInvocation("himi push", flags, shellQuote2),
|
|
@@ -71945,7 +72180,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71945
72180
|
next: [
|
|
71946
72181
|
`himi context --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}`,
|
|
71947
72182
|
`himi screens --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}`,
|
|
71948
|
-
`himi telemetry --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}
|
|
72183
|
+
`himi telemetry --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}`,
|
|
72184
|
+
...afterDraft ? [afterDraft.next] : []
|
|
71949
72185
|
],
|
|
71950
72186
|
promote: draft ? `himi promote --app ${app} --release ${release}${forcedPastErrors ? " --force" : ""}${targetName() !== "local" ? ` --target ${targetName()}` : ""}` : null,
|
|
71951
72187
|
...(outcome.manifest.functions?.length ?? 0) > 0 ? {
|
|
@@ -71989,7 +72225,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71989
72225
|
const displayName = str6(flags.name);
|
|
71990
72226
|
const launchMode = flags.snapshot === true ? "snapshot" : "live";
|
|
71991
72227
|
const packOpts = { createdBy: `himi-cli ${cliVersion()}`, launchMode, ...displayName ? { displayName } : {} };
|
|
71992
|
-
const writePack = (root,
|
|
72228
|
+
const writePack = (root, appName2, out, source) => format === "dir" ? packReleaseToDir2(root, appName2, out, packOpts) : packRelease2(root, appName2, out, { ...packOpts, ...source ? { source } : {} });
|
|
71993
72229
|
const releaseDir = str6(flags["release-dir"]);
|
|
71994
72230
|
if (releaseDir) {
|
|
71995
72231
|
const only = str6(flags.app);
|
|
@@ -72054,7 +72290,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72054
72290
|
}
|
|
72055
72291
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
72056
72292
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
72057
|
-
const built = mkdtempSync4(
|
|
72293
|
+
const built = mkdtempSync4(join63(tmpdir5(), "himi-pack-"));
|
|
72058
72294
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
72059
72295
|
const outcome = await buildReleaseFromContent2(dir, built, {
|
|
72060
72296
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -72259,7 +72495,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72259
72495
|
}));
|
|
72260
72496
|
return 1;
|
|
72261
72497
|
}
|
|
72262
|
-
const archive =
|
|
72498
|
+
const archive = readFileSync77(resolve47(file));
|
|
72263
72499
|
const result = await client2().createPackageShare({
|
|
72264
72500
|
app: opened.header.app,
|
|
72265
72501
|
releaseId: opened.header.releaseId,
|
|
@@ -72319,11 +72555,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72319
72555
|
const app = await appId(dir2);
|
|
72320
72556
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
72321
72557
|
const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
|
|
72322
|
-
temp = mkdtempSync4(
|
|
72558
|
+
temp = mkdtempSync4(join63(tmpdir5(), "himi-run-build-"));
|
|
72323
72559
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
72324
72560
|
const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
|
|
72325
72561
|
servedMissing = initial.missingBundles;
|
|
72326
|
-
source =
|
|
72562
|
+
source = join63(temp, app);
|
|
72327
72563
|
}
|
|
72328
72564
|
const chromeArg = str6(flags.chrome) ?? "preview";
|
|
72329
72565
|
if (chromeArg !== "preview" && chromeArg !== "app") {
|
|
@@ -72359,7 +72595,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72359
72595
|
if (!recordKit) return;
|
|
72360
72596
|
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
72361
72597
|
const failure = record2(served2, { ok: true, at: startedAt });
|
|
72362
|
-
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${
|
|
72598
|
+
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join63(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
|
|
72363
72599
|
await refreshBoard();
|
|
72364
72600
|
};
|
|
72365
72601
|
const retract = async () => {
|
|
@@ -72390,7 +72626,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72390
72626
|
}
|
|
72391
72627
|
const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
|
|
72392
72628
|
const bus = watchKit ? new watchKit.ReloadBus() : void 0;
|
|
72393
|
-
if (watch2) served = mkdtempSync4(
|
|
72629
|
+
if (watch2) served = mkdtempSync4(join63(tmpdir5(), "himi-run-served-"));
|
|
72394
72630
|
const running = await runPackage2(source, {
|
|
72395
72631
|
port,
|
|
72396
72632
|
chrome: chromeArg,
|
|
@@ -72412,8 +72648,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72412
72648
|
await announce(running);
|
|
72413
72649
|
if (watchKit && bus) {
|
|
72414
72650
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
72415
|
-
const live2 =
|
|
72416
|
-
const manifestOf = (tree) => JSON.parse(
|
|
72651
|
+
const live2 = join63(running.releaseRoot, running.app);
|
|
72652
|
+
const manifestOf = (tree) => JSON.parse(readFileSync77(join63(tree, "release-manifest.json"), "utf8"));
|
|
72417
72653
|
let current = manifestOf(live2);
|
|
72418
72654
|
const failed2 = async (message) => {
|
|
72419
72655
|
if (stopping) return;
|
|
@@ -72424,7 +72660,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72424
72660
|
};
|
|
72425
72661
|
rebuild = watchKit.serialize(async () => {
|
|
72426
72662
|
const t0 = Date.now();
|
|
72427
|
-
const next = mkdtempSync4(
|
|
72663
|
+
const next = mkdtempSync4(join63(tmpdir5(), "himi-run-build-"));
|
|
72428
72664
|
try {
|
|
72429
72665
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
72430
72666
|
if (bres.compileErrors.length) {
|
|
@@ -72441,16 +72677,16 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72441
72677
|
return;
|
|
72442
72678
|
}
|
|
72443
72679
|
if (stopping) return;
|
|
72444
|
-
const fresh = manifestOf(
|
|
72680
|
+
const fresh = manifestOf(join63(next, running.app));
|
|
72445
72681
|
const diff = watchKit.diffReleases(current, fresh);
|
|
72446
72682
|
const { describeChanges: describeChanges2, headline: headline2 } = await Promise.resolve().then(() => (init_build_changes(), build_changes_exports));
|
|
72447
|
-
const changes = describeChanges2(live2,
|
|
72683
|
+
const changes = describeChanges2(live2, join63(next, running.app), diff);
|
|
72448
72684
|
const retired = `${live2}.retired-${Date.now()}`;
|
|
72449
72685
|
renameSync7(live2, retired);
|
|
72450
72686
|
try {
|
|
72451
|
-
renameSync7(
|
|
72687
|
+
renameSync7(join63(next, running.app), live2);
|
|
72452
72688
|
} catch {
|
|
72453
|
-
cpSync3(
|
|
72689
|
+
cpSync3(join63(next, running.app), live2, { recursive: true });
|
|
72454
72690
|
}
|
|
72455
72691
|
rmSync14(retired, { recursive: true, force: true });
|
|
72456
72692
|
current = fresh;
|
|
@@ -73060,7 +73296,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73060
73296
|
io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
|
|
73061
73297
|
return 2;
|
|
73062
73298
|
}
|
|
73063
|
-
if (!
|
|
73299
|
+
if (!existsSync65(file)) {
|
|
73064
73300
|
io.error(JSON.stringify({ error: `no such file: ${file}` }));
|
|
73065
73301
|
return 2;
|
|
73066
73302
|
}
|
|
@@ -73116,7 +73352,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73116
73352
|
lintNote: "`himi patch` sends a raw file. Nothing here built or linted your app \u2014 `himi push --only <selector>` is the same edit with the full lint gate in front of it."
|
|
73117
73353
|
};
|
|
73118
73354
|
if (kind === "tokens" || kind === "app-config") {
|
|
73119
|
-
const body =
|
|
73355
|
+
const body = readFileSync77(file, "utf8");
|
|
73120
73356
|
const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
|
|
73121
73357
|
return runReleasePatch({
|
|
73122
73358
|
...common,
|
|
@@ -73131,7 +73367,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73131
73367
|
io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
|
|
73132
73368
|
return 2;
|
|
73133
73369
|
}
|
|
73134
|
-
const descriptor =
|
|
73370
|
+
const descriptor = readFileSync77(file, "utf8");
|
|
73135
73371
|
try {
|
|
73136
73372
|
JSON.parse(descriptor);
|
|
73137
73373
|
} catch (e) {
|
|
@@ -73171,7 +73407,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73171
73407
|
extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
|
|
73172
73408
|
});
|
|
73173
73409
|
}
|
|
73174
|
-
const bytes2 =
|
|
73410
|
+
const bytes2 = readFileSync77(file);
|
|
73175
73411
|
const sha = createHash28("sha256").update(bytes2).digest("hex");
|
|
73176
73412
|
const forScreens = (str6(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
73177
73413
|
if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
|
|
@@ -73315,7 +73551,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73315
73551
|
}
|
|
73316
73552
|
let def;
|
|
73317
73553
|
try {
|
|
73318
|
-
const parsed = JSON.parse(arg.startsWith("@") ?
|
|
73554
|
+
const parsed = JSON.parse(arg.startsWith("@") ? readFileSync77(arg.slice(1), "utf8") : arg);
|
|
73319
73555
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
73320
73556
|
io.error(JSON.stringify({ error: "invalid_definition", problems: [`--definition must be a JSON object, got ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`] }));
|
|
73321
73557
|
return 2;
|
|
@@ -73779,7 +74015,7 @@ ${label2}`);
|
|
|
73779
74015
|
const platform = str6(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
|
|
73780
74016
|
{
|
|
73781
74017
|
const distDir = contentDir(flags);
|
|
73782
|
-
if (
|
|
74018
|
+
if (existsSync65(join63(distDir, "himalaya.content.json"))) {
|
|
73783
74019
|
const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
|
|
73784
74020
|
const errors = issues.filter((i) => i.severity === "error");
|
|
73785
74021
|
for (const i of issues.filter((i2) => i2.severity === "warning")) {
|
|
@@ -74048,7 +74284,7 @@ ${label2}`);
|
|
|
74048
74284
|
const dpxPath = dpxSessionTokenPath();
|
|
74049
74285
|
let dpx;
|
|
74050
74286
|
try {
|
|
74051
|
-
dpx =
|
|
74287
|
+
dpx = readFileSync77(dpxPath, "utf8").trim();
|
|
74052
74288
|
} catch {
|
|
74053
74289
|
io.error(JSON.stringify({ error: `no dpx session at ${dpxPath} \u2014 run \`dpx auth login\` then \`dpx auth token > ${dpxPath}\` (dpx 2.x keeps its own state in ~/.dpx/auth.json and does NOT write the legacy session file), or omit --dpx` }));
|
|
74054
74290
|
return 1;
|
|
@@ -74456,7 +74692,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
74456
74692
|
const path2 = dpxSessionTokenPath();
|
|
74457
74693
|
let raw;
|
|
74458
74694
|
try {
|
|
74459
|
-
raw =
|
|
74695
|
+
raw = readFileSync77(path2, "utf8");
|
|
74460
74696
|
} catch {
|
|
74461
74697
|
io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
|
|
74462
74698
|
return 1;
|