@tokenoftrust/cli 1.3.4-rc.2 → 1.3.4-rc.3
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/package.json +1 -1
- package/src/commands/dev.mjs +90 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/cli",
|
|
3
|
-
"version": "1.3.4-rc.
|
|
3
|
+
"version": "1.3.4-rc.3",
|
|
4
4
|
"description": "Token of Trust developer CLI — check out a tenant store, run it locally with save→reload, and submit it for preview. Installs the `tot` command.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Token of Trust",
|
package/src/commands/dev.mjs
CHANGED
|
@@ -435,12 +435,24 @@ export async function resolveRendererSource(args, { client } = {}) {
|
|
|
435
435
|
* version, so a mismatch is visible, not silent. If nothing exact/minor/≤-ceiling is
|
|
436
436
|
* published, we THROW — a release gap to fix by publishing the aligned runner, not paper over.
|
|
437
437
|
*
|
|
438
|
+
* PIN-DIRECTION DECISION (ADR 0011 — don't relitigate inline): the runner version
|
|
439
|
+
* should be DECLARED BY THE PRODUCT, not derived from the CLI's identity. The
|
|
440
|
+
* ladder below reflects the migration:
|
|
441
|
+
* 1. explicit flag/env pin — developer intent, always wins
|
|
442
|
+
* 2. declaredVersion — the STORE's own `.tot/config.json#runnerVersion`
|
|
443
|
+
* (rust-toolchain.toml-style; the target state)
|
|
444
|
+
* 3. exact CLI-version match — TRANSITIONAL lockstep rung. Delete it (and the
|
|
445
|
+
* lockstep publish regime) once tenant_checkout
|
|
446
|
+
* stamps runnerVersion into every checkout —
|
|
447
|
+
* see ADR 0011 for the exit criteria.
|
|
448
|
+
* 4. CLI-minor / ≤-ceiling — degraded-but-safe fallbacks (never a floating tag)
|
|
449
|
+
*
|
|
438
450
|
* Pure (no I/O) for testability.
|
|
439
451
|
* @param {any} meta npm packument (`dist-tags` + `versions`)
|
|
440
|
-
* @param {{ cliVersion: string, explicitPin?: string|null }} opts
|
|
452
|
+
* @param {{ cliVersion: string, explicitPin?: string|null, declaredVersion?: string|null }} opts
|
|
441
453
|
* @returns {{ version: string, reason: string }}
|
|
442
454
|
*/
|
|
443
|
-
export function pickRunnerVersion(meta, { cliVersion, explicitPin }) {
|
|
455
|
+
export function pickRunnerVersion(meta, { cliVersion, explicitPin, declaredVersion }) {
|
|
444
456
|
const distTags = meta?.["dist-tags"] || {};
|
|
445
457
|
const versions = Object.keys(meta?.versions || {});
|
|
446
458
|
|
|
@@ -457,12 +469,21 @@ export function pickRunnerVersion(meta, { cliVersion, explicitPin }) {
|
|
|
457
469
|
};
|
|
458
470
|
|
|
459
471
|
// 1) Explicit pin (flag/env): the deliberate escape hatch — honored verbatim,
|
|
460
|
-
// INCLUDING above the ceiling (someone testing a newer runner on purpose).
|
|
461
|
-
// the ONLY way past the ceiling; every automatic path below respects it.
|
|
472
|
+
// INCLUDING above the ceiling (someone testing a newer runner on purpose).
|
|
462
473
|
if (explicitPin) {
|
|
463
474
|
return { version: distTags[explicitPin] || explicitPin, reason: `pinned ${explicitPin}` };
|
|
464
475
|
}
|
|
465
476
|
|
|
477
|
+
// 1.5) PRODUCT-DECLARED version (ADR 0011): the store's checkout says which runner
|
|
478
|
+
// it runs — the CLI is just the resolver. Honored verbatim when published, INCLUDING
|
|
479
|
+
// above the ceiling: a declaration newer than this CLI means the CLI is what's stale
|
|
480
|
+
// (the caller nudges an update), not that the product is wrong. A declaration that
|
|
481
|
+
// ISN'T published is a product release gap — fall through to the normal ladder
|
|
482
|
+
// rather than hard-failing the developer's loop (the caller warns loudly).
|
|
483
|
+
if (declaredVersion && versions.includes(declaredVersion)) {
|
|
484
|
+
return { version: declaredVersion, reason: "declared by the store checkout (runnerVersion)" };
|
|
485
|
+
}
|
|
486
|
+
|
|
466
487
|
// 2) EXACT CLI-version match — the primary path for a lockstep release: the runner
|
|
467
488
|
// is published at the SAME version as the CLI (incl. prereleases like 1.3.0-rc.0,
|
|
468
489
|
// which the stable-only minor match below deliberately skips). This is what makes
|
|
@@ -507,6 +528,28 @@ export function pickRunnerVersion(meta, { cliVersion, explicitPin }) {
|
|
|
507
528
|
);
|
|
508
529
|
}
|
|
509
530
|
|
|
531
|
+
/**
|
|
532
|
+
* The runner version a store checkout DECLARES for itself (ADR 0011) — the
|
|
533
|
+
* `runnerVersion` field of `<workspace>/.tot/config.json`. This is the
|
|
534
|
+
* rust-toolchain.toml of the storefront: the PRODUCT (via tenant_checkout
|
|
535
|
+
* stamping it server-side) owns which runtime the store runs; the CLI just
|
|
536
|
+
* resolves it. Returns null when absent/malformed/not-semver — silence is
|
|
537
|
+
* correct: an undeclared checkout falls back to the transitional lockstep rung.
|
|
538
|
+
* Pure-ish (one file read) + exported for tests.
|
|
539
|
+
* @param {string|null|undefined} workspaceDir
|
|
540
|
+
* @returns {string|null}
|
|
541
|
+
*/
|
|
542
|
+
export function declaredRunnerVersion(workspaceDir) {
|
|
543
|
+
if (!workspaceDir) return null;
|
|
544
|
+
try {
|
|
545
|
+
const cfg = JSON.parse(readFileSync(join(workspaceDir, ".tot", "config.json"), "utf8"));
|
|
546
|
+
const v = cfg?.runnerVersion;
|
|
547
|
+
return typeof v === "string" && /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/.test(v) ? v : null;
|
|
548
|
+
} catch {
|
|
549
|
+
return null;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
510
553
|
/** Parse the numeric {major, minor} from a semver (prerelease suffix ignored). Null if unparseable. */
|
|
511
554
|
export function majorMinor(v) {
|
|
512
555
|
const m = /^(\d+)\.(\d+)\./.exec(String(v || ""));
|
|
@@ -531,7 +574,7 @@ function compareStableAsc(a, b) {
|
|
|
531
574
|
* override with `--renderer-version` / TOT_RUNNER_VERSION. Package/registry
|
|
532
575
|
* overridable via env for testing.
|
|
533
576
|
*/
|
|
534
|
-
export async function resolvePublicRendererSource(args, env = process.env) {
|
|
577
|
+
export async function resolvePublicRendererSource(args, env = process.env, { declaredVersion = null } = {}) {
|
|
535
578
|
const pkg = env.TOT_RUNNER_PACKAGE || PUBLIC_RUNNER_PACKAGE;
|
|
536
579
|
const registry = (env.TOT_NPM_REGISTRY || DEFAULT_NPM_REGISTRY).replace(/\/$/, "");
|
|
537
580
|
const explicitPin = args.rendererVersion || env.TOT_RUNNER_VERSION || null;
|
|
@@ -541,11 +584,29 @@ export async function resolvePublicRendererSource(args, env = process.env) {
|
|
|
541
584
|
throw new Error(`npm metadata for ${pkg} failed: HTTP ${res.status} ${res.statusText}`);
|
|
542
585
|
}
|
|
543
586
|
const meta = await res.json();
|
|
544
|
-
const { version, reason } = pickRunnerVersion(meta, { cliVersion: CLI_VERSION, explicitPin });
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
587
|
+
const { version, reason } = pickRunnerVersion(meta, { cliVersion: CLI_VERSION, explicitPin, declaredVersion });
|
|
588
|
+
if (!explicitPin && declaredVersion) {
|
|
589
|
+
if (version === declaredVersion) {
|
|
590
|
+
// The product-declared path (ADR 0011) — the intended steady state, not skew.
|
|
591
|
+
// A declaration NEWER than this CLI means the CLI is the stale half: nudge.
|
|
592
|
+
const mm = majorMinor(declaredVersion);
|
|
593
|
+
const cliMM = majorMinor(CLI_VERSION);
|
|
594
|
+
if (mm && cliMM && (mm.major > cliMM.major || (mm.major === cliMM.major && mm.minor > cliMM.minor))) {
|
|
595
|
+
console.warn(
|
|
596
|
+
` ~ this store declares runner ${declaredVersion}, newer than your CLI (${CLI_VERSION}) — ` +
|
|
597
|
+
`if anything misbehaves: npm i -g @tokenoftrust/cli@latest`,
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
} else {
|
|
601
|
+
console.warn(
|
|
602
|
+
` ⚠ this store declares runner ${declaredVersion} but that version isn't on npm — ` +
|
|
603
|
+
`using ${version} (${reason}). The store's runnerVersion needs a published release.`,
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
} else if (!explicitPin && version !== CLI_VERSION) {
|
|
607
|
+
// No declaration (transitional lockstep regime — ADR 0011): exact is the goal.
|
|
608
|
+
// Resolving something ELSE means CLI/runner releases are skewed — say so LOUDLY
|
|
609
|
+
// instead of silently running a mismatched runner.
|
|
549
610
|
console.warn(
|
|
550
611
|
` ⚠ runner ${version} — no exact @${CLI_VERSION} published (${reason}). ` +
|
|
551
612
|
`CLI/runner versions are SKEWED; publish the runner at ${CLI_VERSION} to align ` +
|
|
@@ -733,26 +794,31 @@ export async function ensureSampleRenderer(args, ctx, { env = process.env, cache
|
|
|
733
794
|
}
|
|
734
795
|
|
|
735
796
|
// kind === "none" — no override, not in the monorepo: fetch the PUBLIC runner
|
|
736
|
-
// from npm
|
|
797
|
+
// from npm. Version = what the STORE declares (ADR 0011), else pinned to this
|
|
798
|
+
// CLI's version (transitional lockstep). No MCP, no entitlement, no login.
|
|
737
799
|
const explicitPin = args.rendererVersion || env.TOT_RUNNER_VERSION || null;
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
//
|
|
742
|
-
//
|
|
743
|
-
//
|
|
744
|
-
//
|
|
800
|
+
const declared = declaredRunnerVersion(args.workspace || ctx?.workspacePath);
|
|
801
|
+
const wantVersion = declared || CLI_VERSION;
|
|
802
|
+
|
|
803
|
+
// Fully-offline fast path: when the WANTED version (declared, else lockstep) is
|
|
804
|
+
// already cached, reuse it without touching npm — honouring "don't hit npm when
|
|
805
|
+
// the RIGHT version is already cached" without ever reusing a version the
|
|
806
|
+
// resolution wouldn't choose. Safe because `public-<version>` only exists if a
|
|
807
|
+
// prior run fetched exactly that version. Skipped when an explicit pin is set
|
|
808
|
+
// (that must go through resolution).
|
|
745
809
|
if (!explicitPin) {
|
|
746
|
-
const exact = pinnedPublicCacheDir(cacheRoot,
|
|
810
|
+
const exact = pinnedPublicCacheDir(cacheRoot, wantVersion);
|
|
747
811
|
if (exact) {
|
|
748
|
-
// Trust-but-verify: a `public-<
|
|
812
|
+
// Trust-but-verify: a `public-<version>` dir SHOULD be a current runner,
|
|
749
813
|
// but if it can't report its own version it predates the --version surface
|
|
750
814
|
// (a corrupt/half-migrated cache) — force a fresh fetch rather than run a
|
|
751
815
|
// runner we can't identify. When it DOES answer, reuse it (fully offline-safe).
|
|
752
816
|
if (probeRunnerVersion(exact)) {
|
|
753
|
-
console.error(
|
|
754
|
-
|
|
755
|
-
|
|
817
|
+
console.error(
|
|
818
|
+
`~ renderer: cached public runner ${wantVersion} (${declared ? "declared by this store" : "matches this CLI"})`,
|
|
819
|
+
);
|
|
820
|
+
setRunnerVersion(wantVersion);
|
|
821
|
+
prunePublicRunnerCache(cacheRoot, wantVersion);
|
|
756
822
|
return exact;
|
|
757
823
|
}
|
|
758
824
|
console.error(`~ renderer: cached runner at ${exact} can't report a version — refetching (forced upgrade)`);
|
|
@@ -762,7 +828,7 @@ export async function ensureSampleRenderer(args, ctx, { env = process.env, cache
|
|
|
762
828
|
|
|
763
829
|
let pub;
|
|
764
830
|
try {
|
|
765
|
-
pub = await resolvePublicRendererSource(args, env);
|
|
831
|
+
pub = await resolvePublicRendererSource(args, env, { declaredVersion: declared });
|
|
766
832
|
} catch (e) {
|
|
767
833
|
// OFFLINE / npm unreachable — no way to resolve the pinned version. Last
|
|
768
834
|
// resort: reuse ANY complete cached runner rather than hard-failing `tot dev`.
|