@wix/himalaya-cli 0.973.0 → 0.975.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 +482 -23
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -18715,6 +18715,7 @@ function shouldRevealError(args) {
|
|
|
18715
18715
|
var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
|
|
18716
18716
|
var init_validation = __esm({
|
|
18717
18717
|
"../../core/ts/src/validation.ts"() {
|
|
18718
|
+
"use strict";
|
|
18718
18719
|
EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
18719
18720
|
URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
18720
18721
|
INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
@@ -22139,6 +22140,7 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
|
|
|
22139
22140
|
var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
|
|
22140
22141
|
var init_worker_subtree = __esm({
|
|
22141
22142
|
"../../core/ts/src/worker-subtree.ts"() {
|
|
22143
|
+
"use strict";
|
|
22142
22144
|
init_worker_subtree_safe_types_generated();
|
|
22143
22145
|
WORKER_SUBTREE_CEILINGS = Object.freeze({
|
|
22144
22146
|
maxEncodedBytes: 65536,
|
|
@@ -39644,7 +39646,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
|
|
|
39644
39646
|
const body = init.body === void 0 || init.body === null ? void 0 : new Uint8Array(await new Response(init.body).arrayBuffer());
|
|
39645
39647
|
const headers2 = Object.fromEntries(new Headers(init.headers).entries());
|
|
39646
39648
|
const request = url.protocol === "https:" ? httpsRequest : httpRequest;
|
|
39647
|
-
const
|
|
39649
|
+
const hostname2 = url.hostname.replace(/^\[|\]$/g, "");
|
|
39648
39650
|
return await new Promise((resolve43, reject) => {
|
|
39649
39651
|
let settled = false;
|
|
39650
39652
|
const finish2 = (fn) => {
|
|
@@ -39654,13 +39656,13 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
|
|
|
39654
39656
|
};
|
|
39655
39657
|
const req = request({
|
|
39656
39658
|
protocol: url.protocol,
|
|
39657
|
-
hostname,
|
|
39659
|
+
hostname: hostname2,
|
|
39658
39660
|
port: url.port || (url.protocol === "https:" ? 443 : 80),
|
|
39659
39661
|
path: `${url.pathname}${url.search}`,
|
|
39660
39662
|
method: init.method ?? "GET",
|
|
39661
39663
|
headers: headers2,
|
|
39662
39664
|
lookup: (_hostname, _options, callback) => callback(null, address, isIP(address)),
|
|
39663
|
-
...url.protocol === "https:" && isIP(
|
|
39665
|
+
...url.protocol === "https:" && isIP(hostname2) === 0 ? { servername: hostname2 } : {}
|
|
39664
39666
|
}, (response) => {
|
|
39665
39667
|
const chunks = [];
|
|
39666
39668
|
let total = 0;
|
|
@@ -48234,9 +48236,9 @@ function isFetchableFontUrl(raw) {
|
|
|
48234
48236
|
if (host.includes(":")) return !isPrivateV6(host);
|
|
48235
48237
|
return true;
|
|
48236
48238
|
}
|
|
48237
|
-
function resolveAll(
|
|
48239
|
+
function resolveAll(hostname2) {
|
|
48238
48240
|
return new Promise((resolve43, reject) => {
|
|
48239
|
-
dnsLookup(
|
|
48241
|
+
dnsLookup(hostname2, { all: true, verbatim: true }, (err, addresses) => {
|
|
48240
48242
|
if (err) reject(err);
|
|
48241
48243
|
else resolve43(addresses);
|
|
48242
48244
|
});
|
|
@@ -51212,9 +51214,9 @@ var init_site_oauth_client = __esm({
|
|
|
51212
51214
|
|
|
51213
51215
|
// src/cli.ts
|
|
51214
51216
|
import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync65, mkdirSync as mkdirSync25, writeFileSync as writeFileSync23, existsSync as existsSync54, rmSync as rmSync9, readdirSync as readdirSync25, statSync as statSync12, lstatSync as lstatSync6, accessSync, constants } from "node:fs";
|
|
51215
|
-
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
51216
|
-
import { createHash as createHash24 } from "node:crypto";
|
|
51217
|
-
import { tmpdir as tmpdir5 } from "node:os";
|
|
51217
|
+
import { execFileSync as execFileSync7, spawnSync as spawnSync5 } from "node:child_process";
|
|
51218
|
+
import { createHash as createHash24, randomUUID as randomUUID3 } from "node:crypto";
|
|
51219
|
+
import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
|
|
51218
51220
|
import { join as join51, resolve as resolve42, relative as relative8, basename as basename11, dirname as dirname30 } from "node:path";
|
|
51219
51221
|
import { fileURLToPath as fileURLToPath24 } from "node:url";
|
|
51220
51222
|
|
|
@@ -54580,6 +54582,19 @@ ${overview}
|
|
|
54580
54582
|
|
|
54581
54583
|
${loop}
|
|
54582
54584
|
|
|
54585
|
+
## Stay on a current CLI
|
|
54586
|
+
|
|
54587
|
+
A stale global install is the single most common cause of "this doesn't work off-repo": the old
|
|
54588
|
+
CLI mislabels its own age as a platform limit, and the error it prints sends you hunting the
|
|
54589
|
+
wrong thing. himi now notices \u2014 when the running build is over a week old it updates itself and
|
|
54590
|
+
re-runs your command (at a terminal it asks first), so in an unattended run this takes care of
|
|
54591
|
+
itself. \`himi upgrade\` does it on demand, and \`himi doctor --json\` reports
|
|
54592
|
+
\`versions.cli\` \u2014 \`running\`, \`latest\`, \`ageDays\`, \`status\`.
|
|
54593
|
+
|
|
54594
|
+
Before concluding that a command is broken or a capability is missing, check you are not on an
|
|
54595
|
+
old build. If a \`--json\` envelope carries an \`upgrade\` key, that is himi telling you this
|
|
54596
|
+
directly. Set \`HIMI_NO_UPDATE_CHECK=1\` in images that must not self-update.
|
|
54597
|
+
|
|
54583
54598
|
## Import paths (in-repo vs off-repo)
|
|
54584
54599
|
|
|
54585
54600
|
Off-repo content packages import \`@wix/himalaya/<pkg>\`. In-repo Himalaya sources import
|
|
@@ -55333,6 +55348,12 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
55333
55348
|
stored control token). --dpx also runs a live
|
|
55334
55349
|
supported "dpx auth status". --json for agents; an
|
|
55335
55350
|
unreachable internal plane carries code:"needs_vpn".
|
|
55351
|
+
himi upgrade [--json] install the newest published CLI and say what moved.
|
|
55352
|
+
himi also does this ITSELF when the running build is
|
|
55353
|
+
over a week old \u2014 unattended it updates and re-runs
|
|
55354
|
+
your command, at a terminal it asks first. Turn that
|
|
55355
|
+
off with HIMI_NO_UPDATE_CHECK=1 (or per-run with
|
|
55356
|
+
--skip-version-check) and use this command instead.
|
|
55336
55357
|
|
|
55337
55358
|
Learn (works offline \u2014 no serve stack needed):
|
|
55338
55359
|
himi guide feature highlights + the headless dev loop + topics
|
|
@@ -55421,6 +55442,7 @@ var COMMANDS = [
|
|
|
55421
55442
|
{ name: "notify", summary: "send a REAL push notification to registered devices (RFC 0036 WS5) \u2014 APNs .p8 over HTTP/2 for iOS, FCM v1 for Android. `send` targets one device (--token / --device <registry id>) or fans out to the whole app (--all), reporting a per-device result; a token the provider says is uninstalled (APNs 410 Unregistered / FCM UNREGISTERED) is auto-disabled, while a merely wrong one (BadDeviceToken \u2014 usually a sandbox/production mismatch) is recorded and left enabled. `tokens` lists the registry. `doctor` reports which credentials resolve and which sender each platform picks. Talks to the admin-server via --admin-url/HIMALAYA_ADMIN_URL, authenticated with --admin-session/HIMALAYA_ADMIN_SESSION. NOT `himi push`, which publishes a release.", required: "send|tokens|doctor [--app <a>] [--token <t> | --device <id> | --all] [--title <s>] [--body <s>] [--link <url>] [--platform ios|android] [--badge <n>] [--channel <id>] [--silent] [--dry-run] [--json]" },
|
|
55422
55443
|
{ name: "site", summary: "PROVISION a Wix project, then analyze or extend it. `create` is the one door that makes a site instead of adopting one: POST /funnel/projects/v1/create (a WIX site, a HEADLESS backend, a BRANDED_APP, or a VIBE site), and for headless it also mints the OAuth app whose id IS the `WIX_CLIENT_ID` \u2014 with --redirect-uri already registered, because an unregistered redirect makes native signInDirect fail at redirect-session. `--verticals` REQUIRES `--template` and reports only what Wix confirmed: measured, installing onto a project created from the BLANK template returns 200 while the vertical's API answers 428 forever, because there is no site for it to attach to (the install asks for CREATE_SITE). A real template ships its verticals installed and populated, and installing further ones onto it then works. It MUTATES your Wix account and needs --yes; without it you get the payload and nothing is sent. `list` is the read-only site inventory (with each site's premium flag, which is what explains an installed-but-428 vertical). Auth is the account-scoped `wix token` (no --site), falling back to WIX_API_KEY + WIX_ACCOUNT_ID. `client` is the same OAuth step for a site that ALREADY exists \u2014 the one himi adopts rather than makes \u2014 so a clientId no longer means a manual trip to the dashboard: `client ensure` reconciles rather than mints, because a site can already carry a client with NO registered redirect and shipping that one fails signInDirect at runtime; it reuses a client that carries --redirect-uri, PATCHes one that matches --name but lacks it (unioning, so another app's redirect survives), and creates only when there is nothing to reuse (--new forces a fresh one). --name IS the idempotency key. `client` auth is SITE-scoped (`wix token --site <msid>`) because minting is owner-of-that-site, and --yes gates every mutation: a site that already has a usable client resolves WITHOUT it, but --write-provisioning needs --yes even then because it rewrites a manifest on disk (the dry run's planned.provisioning names the file). That query endpoint IGNORES paging (measured: query.paging, cursorPaging and a top-level paging all return the full set at offset 0), so when pagingMetadata reports more clients than came back, `ensure` REFUSES EVERY outcome \u2014 create, patch AND reuse. Reuse is refused too because pickClient breaks ties on the OLDEST createdDate, so an omitted older same-named MOBILE client with the same redirect would win a later complete read and the resolved clientId would MOVE between runs \u2014 and it gets written into provisioning.json; convergence is what makes a stray duplicate untidy rather than harmful. --name cannot narrow the query (no filter is sent; the name is applied to the rows after they arrive), so the recovery is the dashboard; --new skips the query entirely. A `patched` result is verified against what Wix STORED \u2014 the redirect list is read off the PATCH response, and re-read via GET when the response omits it, because falling back to the list himi just sent would make the guard pass vacuously on exactly the silent no-op it exists to catch. `client list` is the read-only inventory of a site's clients: act on its `shippable` column rather than `hasRedirect`, because shippable ALSO requires a MOBILE applicationType and `ensure` refuses a WEB client \u2014 a WEB one carrying your redirect looks right and is not a candidate \u2014 and it sets truncated:true rather than presenting a partial inventory as the whole one. `analyze` reads a site into a business-book folder (REST + Playwright, GET-only); `site function` list/get/put/publish/invokes that site's Velo HTTP functions and is not `himi functions` (serve-plane jobs). `--apply` bakes into a brandable shell; `--shell` takes the same names `himi dist --shell` does and defaults to branded-lite, and a shell that ships no prepare:customer is refused by name rather than half-built. It never overwrites any shell's committed apps/<shell>/provisioning.json.", required: "create <name> [--type wix|headless|branded-app|vibe] [--template <guid>] [--verticals stores,bookings,\u2026] [--folder <guid>] [--redirect-uri <uri>] [--no-oauth-app] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | list | client ensure|list --site <msid> [--name <name>] [--redirect-uri <uri>] [--new] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | analyze --client-id <id> --url <https> [--site <msid>] [--out <dir>] [--redirect-uri <uri>] [--apply] [--shell " + SHELL_ENUM + "] | function list|get|put|publish|invoke [--site <msid>] [--url <https>] [--method GET|POST|PUT|DELETE] [--source <file>] [--body <json>] [--publish] [--invoke]" },
|
|
55423
55444
|
{ name: "doctor", summary: 'off-VPN preflight in one shot: probe the PUBLIC data plane (www.wixapis.com \u2014 reachable off-VPN), the INTERNAL serve/control plane for the selected target (VPN-gated), and report auth state (dpx session on disk + stored control token). --dpx additionally runs a live, EADDRINUSE-safe `dpx whoami`. Machine-readable with --json (an unreachable internal plane carries a stable code:"needs_vpn" so an agent branches on the code, not the prose); human-readable otherwise. Never loads the authoring runtime \u2014 works off-repo.', required: "[--target <t>] [--dpx] [--json] [--data-url <url>] [--timeout <ms>]" },
|
|
55445
|
+
{ name: "upgrade", summary: "install the newest published CLI (`npm i -g @wix/himalaya-cli@latest`) and report what moved. This is the explicit door: himi also updates itself when the running build is more than a week old \u2014 unattended it just does it and re-runs your command, at a terminal it asks first \u2014 and `HIMI_NO_UPDATE_CHECK=1` turns that off, leaving this command as the way to catch up. Reports `unchanged` rather than claiming success when npm exits 0 without moving the version, which is what a registry mirror serving its own pinned copy looks like.", required: "[--json]" },
|
|
55424
55446
|
{ name: "push", summary: "lint + build + publish a release (default --draft: servable via ?release= but NOT live). REFUSES to publish on any error unless --force; --strict promotes warnings. Prints preview + agent-context links. The published slug is NAMESPACED per owner \u2014 `<ownerPrefix>.<name>`, composed offline from the control token's ownerPrefix claim, so the CLI and the server derive the identical string and himalaya.content.json is NOT rewritten (a legacy token with no ownerPrefix publishes the declared name unchanged). An app claimed BEFORE namespacing is stored under its FLAT slug, so the claim route answers `alreadyYours` naming that slug and the push adopts it \u2014 reported as `adoptedSlug`, since it is the one case where the published `app` differs from what the declared name composes to. `--no-claim` skips the route that knows this, so a pre-namespacing app pushed with it still fails 403. --visibility public|unlisted decides whether /v1/apps + the Himi Player picker LIST the app (also declarable as `visibility` in himalaya.content.json; omitted, a brand-new app defaults to unlisted \u2014 share by link \u2014 and an existing setting is kept). --account-id names which account owns the app when your Wix session resolves to several (the auto-claim of a brand-new slug cannot guess \u2014 without it a multi-account caller is told to name one). An unforced push of a release that carries SCREENS also refuses when `.himi/ux-audit.json` holds no mobile-UX drive recorded against that release id, or holds one that FAILED (#2955) \u2014 a published draft IS the owner-private preview a customer is handed; `himi ux record` clears it and `--force` overrides it, which the success envelope then says out loud. `--only <selector>` publishes ONLY the named items as a release derived from the app's live release (or `--from-release <id>`), running the identical build + lint gate and simply publishing less; it requires an explicit `--draft` or `--live` because a partial publish has no safe default, never claims a slug, and carries neither attestation nor a source archive (both named in the output). Selectors are comma-separated in ONE `--only`: `changed` (every item whose bytes differ from the base), `screen:<id|glob>`, `bundle:<name>`, `tokens`, `app-config` \u2014 a selected screen drags its logic bundle and a selected bundle drags the screens that reference it, or the bytes land under a key nothing reads.", required: "[--content <dir>] [--draft] [--live] [--force] [--strict] [--label] [--notes] [--visibility public|unlisted] [--no-claim] [--account-id <id>] [--only <selector>] [--from-release <id>] [--accept-regressions] [--accept-partial] [--app <slug>] (--control-token)" },
|
|
55425
55447
|
{ name: "pack", summary: 'write the app as a PORTABLE .himi package \u2014 one self-contained file holding every screen, Tier-5 bundle, token, asset and the app-config. Packages are live by default: they boot bundled content offline, then Himi Player follows its baked-in production ring. `--snapshot` makes a frozen reproducible artifact. Package-supplied origins are never trusted. --format dir writes the same tree unpacked, for static hosting. --release-dir packs a release that is already built on disk (needs --app) instead of rebuilding from source. `--dev` ALSO packs the app\'s own source archive into the container (`source.zip`, header `contents: "dev"`), so the package can be handed to someone who then keeps building \u2014 collected through the same deny-list and secret scan `himi push` uses, and refused if a credential is found. A dev package IS the codebase: it is never the default, it is always labelled in the output, the web host will not open one, and it is archive-only (`--dev --format dir` is refused, because a reader that predates the source entry drops it before hashing a directory and would call the package tampered). Restore one with `himi import`.', required: "[--content <dir>] [--out <file|dir>] [--format zip|dir] [--name <title>] [--snapshot] [--dev] [--strict] [--force] | --release-dir <dir> --app <a>" },
|
|
55426
55448
|
{ name: "import", summary: "turn a `himi pack --dev` package back into an EDITABLE content package \u2014 the file counterpart of `himi pull`, needing no serve plane, no account and no network. Refuses an invalid package before trusting its source (the content hash is recomputed over every entry on open, so the archive is provably the one that was packed), and refuses a RELEASE package by naming the absence \u2014 it carries built output and no source \u2014 rather than reporting a missing file. `--name` re-substitutes the app identity through the same machinery `himi init --template` and `himi pull --name` use, so the restored tree is a NEW app rather than a second copy of the same one, and a name that also appears inside a screen id (`feed` in `feed_home`) is left alone. A non-empty destination needs `--force` and a merge NAMES what it kept (`left: [...]`), the same contract `himi pull --force` has; a shape clash is refused whole before anything is written. There is no `--replace`: a file you were handed is not the plane's per-release archive.", required: "<package.himi> [--out <dir>] [--name <new>] [--force]" },
|
|
@@ -55472,6 +55494,56 @@ function compareVersions2(a, b) {
|
|
|
55472
55494
|
}
|
|
55473
55495
|
return 0;
|
|
55474
55496
|
}
|
|
55497
|
+
var PUBLIC_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
55498
|
+
var WIX_NPM_MIRROR = "https://npm.dev.wixpress.com";
|
|
55499
|
+
var CLI_PACKAGE_PATH = "@wix%2fhimalaya-cli";
|
|
55500
|
+
var TRUSTED_REGISTRIES = /* @__PURE__ */ new Set([PUBLIC_NPM_REGISTRY, WIX_NPM_MIRROR]);
|
|
55501
|
+
function normalizeRegistry(url) {
|
|
55502
|
+
return url?.trim().replace(/\/+$/, "") || void 0;
|
|
55503
|
+
}
|
|
55504
|
+
function isTrustedRegistry(url) {
|
|
55505
|
+
const normalized = normalizeRegistry(url);
|
|
55506
|
+
return normalized !== void 0 && TRUSTED_REGISTRIES.has(normalized);
|
|
55507
|
+
}
|
|
55508
|
+
function trustedConfiguredRegistry(env) {
|
|
55509
|
+
const configured = normalizeRegistry(env.npm_config_registry ?? env.NPM_CONFIG_REGISTRY);
|
|
55510
|
+
return isTrustedRegistry(configured) ? configured : void 0;
|
|
55511
|
+
}
|
|
55512
|
+
async function fetchPackumentFrom(registry, fetchImpl, timeoutMs) {
|
|
55513
|
+
const controller = new AbortController();
|
|
55514
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
55515
|
+
try {
|
|
55516
|
+
const response = await fetchImpl(`${registry.replace(/\/$/, "")}/${CLI_PACKAGE_PATH}`, {
|
|
55517
|
+
headers: { accept: "application/json" },
|
|
55518
|
+
signal: controller.signal
|
|
55519
|
+
});
|
|
55520
|
+
if (!response.ok) return void 0;
|
|
55521
|
+
const json5 = await response.json();
|
|
55522
|
+
const latest = typeof json5?.["dist-tags"]?.latest === "string" ? json5["dist-tags"].latest : void 0;
|
|
55523
|
+
const time = {};
|
|
55524
|
+
for (const [version, when] of Object.entries(json5?.time ?? {})) if (typeof when === "string") time[version] = when;
|
|
55525
|
+
return latest ? { latest, time, registry: normalizeRegistry(registry) ?? registry } : void 0;
|
|
55526
|
+
} catch {
|
|
55527
|
+
return void 0;
|
|
55528
|
+
} finally {
|
|
55529
|
+
clearTimeout(timer);
|
|
55530
|
+
}
|
|
55531
|
+
}
|
|
55532
|
+
async function fetchCliPackument(fetchImpl = fetch, timeoutMs = DOCTOR_TIMEOUT_MS, env = process.env) {
|
|
55533
|
+
const configured = trustedConfiguredRegistry(env);
|
|
55534
|
+
const candidates = configured && configured !== PUBLIC_NPM_REGISTRY ? [configured, PUBLIC_NPM_REGISTRY] : [PUBLIC_NPM_REGISTRY];
|
|
55535
|
+
for (const registry of candidates) {
|
|
55536
|
+
const packument = await fetchPackumentFrom(registry, fetchImpl, timeoutMs);
|
|
55537
|
+
if (packument) return packument;
|
|
55538
|
+
}
|
|
55539
|
+
return void 0;
|
|
55540
|
+
}
|
|
55541
|
+
function ageInDays(publishedAt, now = Date.now()) {
|
|
55542
|
+
if (!publishedAt) return void 0;
|
|
55543
|
+
const at = Date.parse(publishedAt);
|
|
55544
|
+
if (!Number.isFinite(at)) return void 0;
|
|
55545
|
+
return Math.max(0, (now - at) / 864e5);
|
|
55546
|
+
}
|
|
55475
55547
|
function packageVersion(path) {
|
|
55476
55548
|
try {
|
|
55477
55549
|
const version = JSON.parse(readFileSync65(path, "utf8")).version;
|
|
@@ -55501,18 +55573,10 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
|
|
|
55501
55573
|
}
|
|
55502
55574
|
async function doctorVersionReport(running, fetchImpl = fetch, sdk = resolvedSdkVersion()) {
|
|
55503
55575
|
const minimumSdk = "0.33.0";
|
|
55504
|
-
const
|
|
55505
|
-
|
|
55506
|
-
const
|
|
55507
|
-
const
|
|
55508
|
-
try {
|
|
55509
|
-
const response = await fetchImpl(`${registry}/@wix%2fhimalaya-cli`, { headers: { accept: "application/json" }, signal: controller.signal });
|
|
55510
|
-
const json5 = response.ok ? await response.json() : void 0;
|
|
55511
|
-
latest = typeof json5?.["dist-tags"]?.latest === "string" ? json5["dist-tags"].latest : void 0;
|
|
55512
|
-
} catch {
|
|
55513
|
-
} finally {
|
|
55514
|
-
clearTimeout(timer);
|
|
55515
|
-
}
|
|
55576
|
+
const packument = await fetchCliPackument(fetchImpl);
|
|
55577
|
+
const latest = packument?.latest;
|
|
55578
|
+
const publishedAt = packument?.time[running];
|
|
55579
|
+
const ageDays = ageInDays(publishedAt);
|
|
55516
55580
|
const cliOutdated = !!latest && compareVersions2(running, latest) < 0;
|
|
55517
55581
|
const bundled = sdk.source === "bundled";
|
|
55518
55582
|
const sdkOutdated = !bundled && !!sdk.version && compareVersions2(sdk.version, minimumSdk) < 0;
|
|
@@ -55520,6 +55584,8 @@ async function doctorVersionReport(running, fetchImpl = fetch, sdk = resolvedSdk
|
|
|
55520
55584
|
cli: {
|
|
55521
55585
|
running,
|
|
55522
55586
|
...latest ? { latest } : {},
|
|
55587
|
+
...publishedAt ? { publishedAt } : {},
|
|
55588
|
+
...ageDays === void 0 ? {} : { ageDays: Math.round(ageDays * 10) / 10 },
|
|
55523
55589
|
status: latest ? cliOutdated ? "outdated" : "current" : "unknown",
|
|
55524
55590
|
...cliOutdated ? { hint: "Upgrade: npm i -g @wix/himalaya-cli@latest" } : {}
|
|
55525
55591
|
},
|
|
@@ -55535,6 +55601,329 @@ function formatSdkVersionLine(sdk) {
|
|
|
55535
55601
|
if (sdk.source === "bundled") return `sdk: bundled (${sdk.resolved ?? "unknown"})`;
|
|
55536
55602
|
return `sdk: ${sdk.resolved ?? "not installed"} (minimum ${sdk.minimum}; ${sdk.status})`;
|
|
55537
55603
|
}
|
|
55604
|
+
var CLI_PACKAGE = "@wix/himalaya-cli";
|
|
55605
|
+
var UNPUBLISHED_CLI_VERSION = "0.1.0";
|
|
55606
|
+
var UPDATE_MAX_AGE_DAYS = 7;
|
|
55607
|
+
var UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
55608
|
+
var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
|
|
55609
|
+
var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
|
|
55610
|
+
function updateCachePath(env = process.env) {
|
|
55611
|
+
return env.HIMI_UPDATE_CACHE_FILE ?? join51(homedir7(), ".himalaya", "update-check.json");
|
|
55612
|
+
}
|
|
55613
|
+
function readUpdateCache(path) {
|
|
55614
|
+
try {
|
|
55615
|
+
const parsed = JSON.parse(readFileSync65(path, "utf8"));
|
|
55616
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
55617
|
+
} catch {
|
|
55618
|
+
return {};
|
|
55619
|
+
}
|
|
55620
|
+
}
|
|
55621
|
+
function writeUpdateCache(path, cache) {
|
|
55622
|
+
try {
|
|
55623
|
+
mkdirSync25(dirname30(path), { recursive: true, mode: 448 });
|
|
55624
|
+
writeFileSync23(path, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
|
|
55625
|
+
} catch {
|
|
55626
|
+
}
|
|
55627
|
+
}
|
|
55628
|
+
function updateCheckSuppression(running, command, env = process.env, cwd = process.cwd()) {
|
|
55629
|
+
if (env[UPDATE_REEXEC_ENV] === "1") return "already-updated";
|
|
55630
|
+
if (env.HIMI_NO_UPDATE_CHECK === "1") return "opted-out";
|
|
55631
|
+
if (command === "upgrade" || command === "doctor") return "own-command";
|
|
55632
|
+
if (running === UNPUBLISHED_CLI_VERSION) return "unpublished";
|
|
55633
|
+
if (isHimalayaMonorepoCheckout(cwd)) return "monorepo";
|
|
55634
|
+
return void 0;
|
|
55635
|
+
}
|
|
55636
|
+
function decideUpdateAction(input) {
|
|
55637
|
+
if (!input.latest || compareVersions2(input.running, input.latest) >= 0) return "skip";
|
|
55638
|
+
if (input.ageDays === void 0 || input.ageDays < input.maxAgeDays) return "skip";
|
|
55639
|
+
if (!input.prefixWritable()) return "warn";
|
|
55640
|
+
return input.interactive ? "prompt" : "update";
|
|
55641
|
+
}
|
|
55642
|
+
function globalNodeModulesRoot() {
|
|
55643
|
+
try {
|
|
55644
|
+
const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
55645
|
+
return root || void 0;
|
|
55646
|
+
} catch {
|
|
55647
|
+
return void 0;
|
|
55648
|
+
}
|
|
55649
|
+
}
|
|
55650
|
+
function globalPrefixWritable() {
|
|
55651
|
+
const root = globalNodeModulesRoot();
|
|
55652
|
+
if (!root) return false;
|
|
55653
|
+
try {
|
|
55654
|
+
accessSync(root, constants.W_OK);
|
|
55655
|
+
return true;
|
|
55656
|
+
} catch {
|
|
55657
|
+
return false;
|
|
55658
|
+
}
|
|
55659
|
+
}
|
|
55660
|
+
function npmInstallArgs(registry, version) {
|
|
55661
|
+
const pinned = `${normalizeRegistry(registry) ?? registry}/`;
|
|
55662
|
+
return ["i", "-g", `${CLI_PACKAGE}@${version}`, `--registry=${pinned}`, `--@wix:registry=${pinned}`];
|
|
55663
|
+
}
|
|
55664
|
+
var INSTALLABLE_SPEC = /^(?:latest|\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$/;
|
|
55665
|
+
function createUpdateRunner(spawn5 = spawnSync5) {
|
|
55666
|
+
return {
|
|
55667
|
+
install: async (registry, version) => {
|
|
55668
|
+
if (!isTrustedRegistry(registry)) return { ok: false, detail: `refusing untrusted registry ${registry}` };
|
|
55669
|
+
if (!INSTALLABLE_SPEC.test(version)) return { ok: false, detail: `refusing install spec ${JSON.stringify(version)}` };
|
|
55670
|
+
const result = spawn5("npm", npmInstallArgs(registry, version), {
|
|
55671
|
+
// npm's stdout goes to OUR stderr: in `himi <cmd> --json | jq` (and `himi upgrade --json`) its
|
|
55672
|
+
// "added 212 packages" would otherwise land in stdout ahead of the envelope and break the
|
|
55673
|
+
// parse — the agent case this whole feature exists for (#2985 review). And no stdin: an
|
|
55674
|
+
// install needs none, and must not consume input piped to the command we are about to re-run.
|
|
55675
|
+
stdio: ["ignore", 2, 2],
|
|
55676
|
+
cwd: homedir7()
|
|
55677
|
+
});
|
|
55678
|
+
if (result.error) return { ok: false, detail: result.error.message };
|
|
55679
|
+
return result.status === 0 ? { ok: true } : { ok: false, detail: `npm exited ${result.status}` };
|
|
55680
|
+
},
|
|
55681
|
+
installedVersion: () => {
|
|
55682
|
+
const root = globalNodeModulesRoot();
|
|
55683
|
+
return root ? packageVersion(join51(root, "@wix", "himalaya-cli", "package.json")) : void 0;
|
|
55684
|
+
},
|
|
55685
|
+
reexec: (argv) => {
|
|
55686
|
+
const root = globalNodeModulesRoot();
|
|
55687
|
+
const entry = root ? join51(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
|
|
55688
|
+
if (!entry || !existsSync54(entry)) return void 0;
|
|
55689
|
+
const result = spawnSync5(process.execPath, [entry, ...argv], {
|
|
55690
|
+
// inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
|
|
55691
|
+
stdio: "inherit",
|
|
55692
|
+
env: { ...process.env, [UPDATE_REEXEC_ENV]: "1" }
|
|
55693
|
+
});
|
|
55694
|
+
return result.status ?? 1;
|
|
55695
|
+
},
|
|
55696
|
+
confirm: async (question) => {
|
|
55697
|
+
const { createInterface } = await import("node:readline/promises");
|
|
55698
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
55699
|
+
try {
|
|
55700
|
+
const answer = (await rl.question(question)).trim().toLowerCase();
|
|
55701
|
+
return answer === "" || answer === "y" || answer === "yes";
|
|
55702
|
+
} catch {
|
|
55703
|
+
return false;
|
|
55704
|
+
} finally {
|
|
55705
|
+
rl.close();
|
|
55706
|
+
}
|
|
55707
|
+
}
|
|
55708
|
+
};
|
|
55709
|
+
}
|
|
55710
|
+
var defaultUpdateRunner = createUpdateRunner();
|
|
55711
|
+
var UPDATE_LOCK_REPORT_AFTER_MS = 60 * 60 * 1e3;
|
|
55712
|
+
function thisHost() {
|
|
55713
|
+
return hostname().replace(/\s+/g, "_");
|
|
55714
|
+
}
|
|
55715
|
+
function lockStamp(now) {
|
|
55716
|
+
return `${now} ${process.pid} ${thisHost()} ${randomUUID3()}`;
|
|
55717
|
+
}
|
|
55718
|
+
function processAlive(pid) {
|
|
55719
|
+
try {
|
|
55720
|
+
process.kill(pid, 0);
|
|
55721
|
+
return true;
|
|
55722
|
+
} catch (error) {
|
|
55723
|
+
return error.code === "EPERM";
|
|
55724
|
+
}
|
|
55725
|
+
}
|
|
55726
|
+
function isAbandoned(content) {
|
|
55727
|
+
const [, pid, host] = content.split(" ");
|
|
55728
|
+
const owner = Number.parseInt(pid, 10);
|
|
55729
|
+
return Number.isFinite(owner) && owner > 0 && host === thisHost() && !processAlive(owner);
|
|
55730
|
+
}
|
|
55731
|
+
function staleUpdateLockFile(cachePath, now) {
|
|
55732
|
+
for (const path of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
|
|
55733
|
+
let content;
|
|
55734
|
+
try {
|
|
55735
|
+
content = readFileSync65(path, "utf8");
|
|
55736
|
+
} catch {
|
|
55737
|
+
continue;
|
|
55738
|
+
}
|
|
55739
|
+
const stamped = Number.parseInt(content.split(" ")[0], 10);
|
|
55740
|
+
let since = stamped;
|
|
55741
|
+
if (!Number.isFinite(since)) {
|
|
55742
|
+
try {
|
|
55743
|
+
since = statSync12(path).mtimeMs;
|
|
55744
|
+
} catch {
|
|
55745
|
+
continue;
|
|
55746
|
+
}
|
|
55747
|
+
}
|
|
55748
|
+
if (now - since >= UPDATE_LOCK_REPORT_AFTER_MS) return path;
|
|
55749
|
+
}
|
|
55750
|
+
return void 0;
|
|
55751
|
+
}
|
|
55752
|
+
function acquireUpdateLock(cachePath, now, hooks = {}) {
|
|
55753
|
+
const lockPath = `${cachePath}.lock`;
|
|
55754
|
+
const breakPath = `${cachePath}.lock.break`;
|
|
55755
|
+
const mine = lockStamp(now);
|
|
55756
|
+
const readLock = (path) => {
|
|
55757
|
+
try {
|
|
55758
|
+
return readFileSync65(path, "utf8");
|
|
55759
|
+
} catch {
|
|
55760
|
+
return void 0;
|
|
55761
|
+
}
|
|
55762
|
+
};
|
|
55763
|
+
const tryCreate = (path) => {
|
|
55764
|
+
try {
|
|
55765
|
+
writeFileSync23(path, mine, { flag: "wx", mode: 384 });
|
|
55766
|
+
return true;
|
|
55767
|
+
} catch {
|
|
55768
|
+
return false;
|
|
55769
|
+
}
|
|
55770
|
+
};
|
|
55771
|
+
const removeIfMine = (path) => {
|
|
55772
|
+
try {
|
|
55773
|
+
if (readLock(path) === mine) rmSync9(path, { force: true });
|
|
55774
|
+
} catch {
|
|
55775
|
+
}
|
|
55776
|
+
};
|
|
55777
|
+
const release = () => removeIfMine(lockPath);
|
|
55778
|
+
try {
|
|
55779
|
+
mkdirSync25(dirname30(lockPath), { recursive: true, mode: 448 });
|
|
55780
|
+
} catch {
|
|
55781
|
+
return () => {
|
|
55782
|
+
};
|
|
55783
|
+
}
|
|
55784
|
+
try {
|
|
55785
|
+
if (tryCreate(lockPath)) return release;
|
|
55786
|
+
const held = readLock(lockPath);
|
|
55787
|
+
if (held === void 0) return tryCreate(lockPath) ? release : void 0;
|
|
55788
|
+
if (!isAbandoned(held)) return void 0;
|
|
55789
|
+
hooks.beforeBreak?.();
|
|
55790
|
+
if (!tryCreate(breakPath)) return void 0;
|
|
55791
|
+
try {
|
|
55792
|
+
const current = readLock(lockPath);
|
|
55793
|
+
hooks.underBreakLock?.();
|
|
55794
|
+
if (current === void 0) return tryCreate(lockPath) ? release : void 0;
|
|
55795
|
+
if (!isAbandoned(current)) return void 0;
|
|
55796
|
+
rmSync9(lockPath, { force: true });
|
|
55797
|
+
return tryCreate(lockPath) ? release : void 0;
|
|
55798
|
+
} finally {
|
|
55799
|
+
removeIfMine(breakPath);
|
|
55800
|
+
}
|
|
55801
|
+
} catch {
|
|
55802
|
+
return void 0;
|
|
55803
|
+
}
|
|
55804
|
+
}
|
|
55805
|
+
function formatStaleLine(running, latest, ageDays) {
|
|
55806
|
+
const days = Math.round(ageDays);
|
|
55807
|
+
return `himi v${running} is ${days} day${days === 1 ? "" : "s"} old (latest ${latest})`;
|
|
55808
|
+
}
|
|
55809
|
+
function upgradeEnvelope(outcome) {
|
|
55810
|
+
return {
|
|
55811
|
+
running: outcome.running,
|
|
55812
|
+
...outcome.latest ? { latest: outcome.latest } : {},
|
|
55813
|
+
...outcome.ageDays === void 0 ? {} : { ageDays: outcome.ageDays },
|
|
55814
|
+
action: outcome.action,
|
|
55815
|
+
command: `npm i -g ${CLI_PACKAGE}@latest`,
|
|
55816
|
+
...outcome.detail ? { detail: outcome.detail } : {}
|
|
55817
|
+
};
|
|
55818
|
+
}
|
|
55819
|
+
async function maybeSelfUpdate(argv, io, opts = {}) {
|
|
55820
|
+
const env = opts.env ?? process.env;
|
|
55821
|
+
const running = opts.running ?? cliVersion();
|
|
55822
|
+
const command = opts.command ?? "";
|
|
55823
|
+
if (updateCheckSuppression(running, command, env, opts.cwd ?? process.cwd())) return void 0;
|
|
55824
|
+
const now = opts.now ?? Date.now();
|
|
55825
|
+
const cachePath = opts.cachePath ?? updateCachePath(env);
|
|
55826
|
+
const cache = readUpdateCache(cachePath);
|
|
55827
|
+
if (cache.snoozedUntil && Date.parse(cache.snoozedUntil) > now) return void 0;
|
|
55828
|
+
let latest = cache.latest;
|
|
55829
|
+
let runningPublishedAt = cache.runningPublishedAt;
|
|
55830
|
+
const checkedAt = cache.checkedAt ? Date.parse(cache.checkedAt) : Number.NaN;
|
|
55831
|
+
const describesThisBuild = cache.running === running;
|
|
55832
|
+
const fresh = Number.isFinite(checkedAt) && now - checkedAt < UPDATE_CHECK_INTERVAL_MS && describesThisBuild;
|
|
55833
|
+
if (!describesThisBuild) runningPublishedAt = void 0;
|
|
55834
|
+
let answeredBy;
|
|
55835
|
+
let answeredLatest;
|
|
55836
|
+
if (!fresh) {
|
|
55837
|
+
const packument = await fetchCliPackument(opts.fetchImpl ?? fetch, DOCTOR_TIMEOUT_MS, env);
|
|
55838
|
+
if (packument) {
|
|
55839
|
+
latest = packument.latest;
|
|
55840
|
+
runningPublishedAt = packument.time[running];
|
|
55841
|
+
answeredBy = packument.registry;
|
|
55842
|
+
answeredLatest = packument.latest;
|
|
55843
|
+
writeUpdateCache(cachePath, { ...cache, running, checkedAt: new Date(now).toISOString(), latest, runningPublishedAt });
|
|
55844
|
+
}
|
|
55845
|
+
}
|
|
55846
|
+
const ageDays = ageInDays(runningPublishedAt, now);
|
|
55847
|
+
const fromEnv = Number(env.HIMI_UPDATE_MAX_AGE_DAYS);
|
|
55848
|
+
const maxAgeDays = opts.maxAgeDays ?? (fromEnv > 0 ? fromEnv : UPDATE_MAX_AGE_DAYS);
|
|
55849
|
+
const interactive = opts.interactive ?? (io.isTTY === true && process.stdin.isTTY === true);
|
|
55850
|
+
const action = decideUpdateAction({
|
|
55851
|
+
running,
|
|
55852
|
+
latest,
|
|
55853
|
+
ageDays,
|
|
55854
|
+
maxAgeDays,
|
|
55855
|
+
interactive,
|
|
55856
|
+
prefixWritable: opts.prefixWritable ?? globalPrefixWritable
|
|
55857
|
+
});
|
|
55858
|
+
if (action === "skip" || !latest || ageDays === void 0) return void 0;
|
|
55859
|
+
const base = { running, latest, ageDays: Math.round(ageDays * 10) / 10, command };
|
|
55860
|
+
const stale = formatStaleLine(running, latest, ageDays);
|
|
55861
|
+
if (action === "warn") {
|
|
55862
|
+
io.error(`${stale} \u2014 npm i -g ${CLI_PACKAGE}@latest`);
|
|
55863
|
+
return { ...base, action: "warned", detail: "global prefix is not writable" };
|
|
55864
|
+
}
|
|
55865
|
+
const runner2 = opts.runner ?? defaultUpdateRunner;
|
|
55866
|
+
if (action === "prompt") {
|
|
55867
|
+
const yes = await runner2.confirm(`${stale}. Update now? [Y/n] `);
|
|
55868
|
+
if (!yes) {
|
|
55869
|
+
writeUpdateCache(cachePath, {
|
|
55870
|
+
running,
|
|
55871
|
+
latest,
|
|
55872
|
+
runningPublishedAt,
|
|
55873
|
+
checkedAt: new Date(now).toISOString(),
|
|
55874
|
+
snoozedUntil: new Date(now + UPDATE_SNOOZE_MS).toISOString()
|
|
55875
|
+
});
|
|
55876
|
+
return { ...base, action: "declined" };
|
|
55877
|
+
}
|
|
55878
|
+
}
|
|
55879
|
+
const releaseLock = opts.acquireLock === void 0 ? acquireUpdateLock(cachePath, now) : opts.acquireLock();
|
|
55880
|
+
if (!releaseLock) {
|
|
55881
|
+
const blocker = staleUpdateLockFile(cachePath, now);
|
|
55882
|
+
if (blocker) io.error(`${stale}, but self-update has been blocked for over an hour by ${blocker} \u2014 if no himi is running, delete it`);
|
|
55883
|
+
return void 0;
|
|
55884
|
+
}
|
|
55885
|
+
try {
|
|
55886
|
+
if (!answeredBy) {
|
|
55887
|
+
const again = await fetchCliPackument(opts.fetchImpl ?? fetch, DOCTOR_TIMEOUT_MS, env);
|
|
55888
|
+
answeredBy = again?.registry;
|
|
55889
|
+
answeredLatest = again?.latest;
|
|
55890
|
+
}
|
|
55891
|
+
if (!answeredBy || !answeredLatest || compareVersions2(answeredLatest, running) <= 0) {
|
|
55892
|
+
if (answeredBy && answeredLatest) {
|
|
55893
|
+
writeUpdateCache(cachePath, { ...cache, running, latest: answeredLatest, runningPublishedAt, checkedAt: new Date(now).toISOString() });
|
|
55894
|
+
}
|
|
55895
|
+
return void 0;
|
|
55896
|
+
}
|
|
55897
|
+
const installFrom = answeredBy;
|
|
55898
|
+
const target = answeredLatest;
|
|
55899
|
+
io.error(`${stale} \u2014 updating to ${target}\u2026`);
|
|
55900
|
+
const installed = await runner2.install(installFrom, target);
|
|
55901
|
+
if (!installed.ok) {
|
|
55902
|
+
io.error(` update failed (${installed.detail ?? "unknown error"}) via ${installFrom} \u2014 continuing on v${running}`);
|
|
55903
|
+
return { ...base, action: "failed", detail: installed.detail };
|
|
55904
|
+
}
|
|
55905
|
+
const after = runner2.installedVersion();
|
|
55906
|
+
if (!after || compareVersions2(after, running) <= 0) {
|
|
55907
|
+
io.error(` npm reported success but v${running} is still installed \u2014 continuing without re-running`);
|
|
55908
|
+
return { ...base, action: "failed", detail: "version did not change" };
|
|
55909
|
+
}
|
|
55910
|
+
writeUpdateCache(cachePath, {
|
|
55911
|
+
running: after,
|
|
55912
|
+
latest: target,
|
|
55913
|
+
checkedAt: new Date(now).toISOString(),
|
|
55914
|
+
...cache.snoozedUntil ? { snoozedUntil: cache.snoozedUntil } : {}
|
|
55915
|
+
});
|
|
55916
|
+
io.error(` installed ${after} \u2014 re-running: himi ${argv.join(" ")}`);
|
|
55917
|
+
const exitCode = runner2.reexec(argv);
|
|
55918
|
+
if (exitCode === void 0) {
|
|
55919
|
+
io.error(` could not locate the new install to re-run \u2014 continuing on v${running}`);
|
|
55920
|
+
return { ...base, action: "failed", detail: "new entry not found" };
|
|
55921
|
+
}
|
|
55922
|
+
return { ...base, latest: after, action: "updated", exitCode };
|
|
55923
|
+
} finally {
|
|
55924
|
+
releaseLock();
|
|
55925
|
+
}
|
|
55926
|
+
}
|
|
55538
55927
|
function helpJson() {
|
|
55539
55928
|
return {
|
|
55540
55929
|
cli: "himi",
|
|
@@ -56587,11 +56976,16 @@ async function producedWidgetFamilies(dir) {
|
|
|
56587
56976
|
}
|
|
56588
56977
|
return { families, source: "dist/bundles" };
|
|
56589
56978
|
}
|
|
56590
|
-
async function run(argv, io = defaultIO) {
|
|
56979
|
+
async function run(argv, io = defaultIO, deps = {}) {
|
|
56591
56980
|
const { _: pos, flags } = parseFlags(argv);
|
|
56592
56981
|
const flagErrors = switchFlagErrors(argv);
|
|
56593
56982
|
const command = pos[0];
|
|
56594
|
-
|
|
56983
|
+
let updateNotice;
|
|
56984
|
+
const print = (o) => io.log(JSON.stringify(
|
|
56985
|
+
updateNotice && o && typeof o === "object" && !Array.isArray(o) ? { ...o, upgrade: upgradeEnvelope(updateNotice) } : o,
|
|
56986
|
+
null,
|
|
56987
|
+
2
|
|
56988
|
+
));
|
|
56595
56989
|
if (flags.version === true || command === "version" || pos.includes("-v")) {
|
|
56596
56990
|
const v = cliVersion();
|
|
56597
56991
|
io.log(flags.json ? JSON.stringify({ himi: v }, null, 2) : `himi v${v}`);
|
|
@@ -56609,6 +57003,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
56609
57003
|
io.error(JSON.stringify({ ok: false, error: "invalid_flag_value", problems: flagErrors, hint: "run `himi help` for the flag grammar." }));
|
|
56610
57004
|
return 2;
|
|
56611
57005
|
}
|
|
57006
|
+
if (flags["skip-version-check"] !== true) {
|
|
57007
|
+
const update = await maybeSelfUpdate(argv, io, { command, ...deps.selfUpdate });
|
|
57008
|
+
if (update?.exitCode !== void 0) return update.exitCode;
|
|
57009
|
+
if (update) updateNotice = update;
|
|
57010
|
+
}
|
|
56612
57011
|
const contextualDefaultTarget = defaultTargetForCommand(command, contentDir(flags));
|
|
56613
57012
|
const targetName = () => resolveTargetName({ target: str5(flags.target), defaultTarget: contextualDefaultTarget });
|
|
56614
57013
|
const client2 = () => new ServeCliClient(
|
|
@@ -60967,6 +61366,45 @@ ${label2}`);
|
|
|
60967
61366
|
});
|
|
60968
61367
|
return 0;
|
|
60969
61368
|
}
|
|
61369
|
+
case "upgrade": {
|
|
61370
|
+
const up = deps.selfUpdate ?? {};
|
|
61371
|
+
const runner2 = up.runner ?? defaultUpdateRunner;
|
|
61372
|
+
const env = up.env ?? process.env;
|
|
61373
|
+
const before = cliVersion();
|
|
61374
|
+
const lockFile = `${up.cachePath ?? updateCachePath(env)}.lock`;
|
|
61375
|
+
const releaseLock = up.acquireLock ? up.acquireLock() : acquireUpdateLock(up.cachePath ?? updateCachePath(env), Date.now());
|
|
61376
|
+
if (!releaseLock) {
|
|
61377
|
+
const hint = `another himi process is updating right now \u2014 try again in a minute. If no himi is running, delete ${lockFile} (and ${lockFile}.break if present)`;
|
|
61378
|
+
if (flags.json) print({ ok: false, error: "update_in_progress", running: before, lock: lockFile, hint });
|
|
61379
|
+
else io.error(hint);
|
|
61380
|
+
return 1;
|
|
61381
|
+
}
|
|
61382
|
+
try {
|
|
61383
|
+
const answered = await fetchCliPackument(up.fetchImpl ?? fetch, DOCTOR_TIMEOUT_MS, env);
|
|
61384
|
+
const registry = answered?.registry ?? trustedConfiguredRegistry(env) ?? PUBLIC_NPM_REGISTRY;
|
|
61385
|
+
if (answered?.latest && compareVersions2(answered.latest, before) <= 0) {
|
|
61386
|
+
if (flags.json) print({ ok: true, running: before, installed: before, changed: false, registry, latest: answered.latest });
|
|
61387
|
+
else io.log(`himi ${before} (unchanged \u2014 ${registry} has nothing newer; its latest is ${answered.latest})`);
|
|
61388
|
+
return 0;
|
|
61389
|
+
}
|
|
61390
|
+
const version = answered?.latest ?? "latest";
|
|
61391
|
+
io.error(`upgrading ${CLI_PACKAGE} (running v${before}) to ${version} from ${registry}\u2026`);
|
|
61392
|
+
const installed = await runner2.install(registry, version);
|
|
61393
|
+
if (!installed.ok) {
|
|
61394
|
+
const detail = installed.detail ?? "unknown error";
|
|
61395
|
+
if (flags.json) print({ ok: false, error: "upgrade_failed", running: before, registry, detail });
|
|
61396
|
+
else io.error(`upgrade failed (${detail}) via ${registry}`);
|
|
61397
|
+
return 1;
|
|
61398
|
+
}
|
|
61399
|
+
const after = runner2.installedVersion();
|
|
61400
|
+
const moved = !!after && compareVersions2(after, before) > 0;
|
|
61401
|
+
if (flags.json) print({ ok: true, running: before, installed: after, changed: moved, registry });
|
|
61402
|
+
else io.log(moved ? `himi ${before} \u2192 ${after}` : `himi ${before} (unchanged \u2014 the registry has nothing newer to install)`);
|
|
61403
|
+
return 0;
|
|
61404
|
+
} finally {
|
|
61405
|
+
releaseLock();
|
|
61406
|
+
}
|
|
61407
|
+
}
|
|
60970
61408
|
case "doctor": {
|
|
60971
61409
|
const target = targetName();
|
|
60972
61410
|
const timeoutMs = Number(str5(flags.timeout)) > 0 ? Number(str5(flags.timeout)) : DOCTOR_TIMEOUT_MS;
|
|
@@ -61419,36 +61857,50 @@ if (isMain) {
|
|
|
61419
61857
|
});
|
|
61420
61858
|
}
|
|
61421
61859
|
export {
|
|
61860
|
+
CLI_PACKAGE,
|
|
61422
61861
|
ConfigLoadError,
|
|
61423
61862
|
GIT_FLAG_STORE_HALF_WRITE_NOTE,
|
|
61424
61863
|
GIT_FLAG_STORE_NOTE,
|
|
61425
61864
|
PLACEHOLDER_CLIENT_ID,
|
|
61426
61865
|
PLACEHOLDER_SITE_URL,
|
|
61427
61866
|
PREVIEW_TOKEN_NOTE,
|
|
61867
|
+
PUBLIC_NPM_REGISTRY,
|
|
61428
61868
|
PUBLIC_WIX_API_BASE,
|
|
61869
|
+
WIX_NPM_MIRROR,
|
|
61870
|
+
acquireUpdateLock,
|
|
61871
|
+
ageInDays,
|
|
61429
61872
|
autoClaimSlug,
|
|
61430
61873
|
buildDoctorReport,
|
|
61431
61874
|
compareVersions2 as compareVersions,
|
|
61875
|
+
createUpdateRunner,
|
|
61432
61876
|
credentialKind,
|
|
61433
61877
|
credentialSwapNotice,
|
|
61878
|
+
decideUpdateAction,
|
|
61434
61879
|
decodeControlTokenClaims,
|
|
61435
61880
|
defaultTargetForCommand,
|
|
61881
|
+
defaultUpdateRunner,
|
|
61436
61882
|
diagnoseBody,
|
|
61437
61883
|
doctorVersionReport,
|
|
61438
61884
|
executableOnPath,
|
|
61885
|
+
fetchCliPackument,
|
|
61439
61886
|
foreignPlaneError,
|
|
61440
61887
|
formatSdkVersionLine,
|
|
61888
|
+
formatStaleLine,
|
|
61889
|
+
globalPrefixWritable,
|
|
61441
61890
|
humanDuration,
|
|
61442
61891
|
inspectControlToken,
|
|
61443
61892
|
isHimalayaMonorepoCheckout,
|
|
61444
61893
|
isLoopbackBase,
|
|
61445
61894
|
isPublicTarget,
|
|
61895
|
+
isTrustedRegistry,
|
|
61446
61896
|
loginModeMark,
|
|
61447
61897
|
loginModeReport,
|
|
61448
61898
|
loopbackTargetWarning,
|
|
61449
61899
|
materializeForPreview,
|
|
61900
|
+
maybeSelfUpdate,
|
|
61450
61901
|
nativeConfigAdvisories,
|
|
61451
61902
|
nativeConfigTokenNotice,
|
|
61903
|
+
npmInstallArgs,
|
|
61452
61904
|
ownerPlaneHint,
|
|
61453
61905
|
ownerPlaneIsDark,
|
|
61454
61906
|
parseFlags,
|
|
@@ -61468,6 +61920,7 @@ export {
|
|
|
61468
61920
|
probeControlToken,
|
|
61469
61921
|
probeReachable,
|
|
61470
61922
|
pushAuthHint,
|
|
61923
|
+
readUpdateCache,
|
|
61471
61924
|
renderDataSource,
|
|
61472
61925
|
renderDeviceWidths,
|
|
61473
61926
|
resolveAppSlug,
|
|
@@ -61478,12 +61931,18 @@ export {
|
|
|
61478
61931
|
serveUnreachableHint,
|
|
61479
61932
|
servesAll,
|
|
61480
61933
|
shellShaDivergenceWarnings,
|
|
61934
|
+
staleUpdateLockFile,
|
|
61481
61935
|
switchFlagErrors,
|
|
61482
61936
|
templatePreviewAuthError,
|
|
61483
61937
|
tokenCoversApp,
|
|
61938
|
+
trustedConfiguredRegistry,
|
|
61939
|
+
updateCachePath,
|
|
61940
|
+
updateCheckSuppression,
|
|
61941
|
+
upgradeEnvelope,
|
|
61484
61942
|
uxHandoverHint,
|
|
61485
61943
|
uxHandoverNote,
|
|
61486
61944
|
uxHandoverOverride,
|
|
61487
61945
|
wixPlayerTestflightTarget,
|
|
61488
|
-
writePngFile
|
|
61946
|
+
writePngFile,
|
|
61947
|
+
writeUpdateCache
|
|
61489
61948
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.975.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"artifactId": "himalaya-cli"
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
|
-
"falconPackageHash": "
|
|
67
|
+
"falconPackageHash": "ac291974b49df3a7c0844b15d82c21cb6d2af2409ad4d2b53aa35b5b"
|
|
68
68
|
}
|