@tokenoftrust/cli 2.4.6 → 2.4.8
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/README.md +1 -1
- package/package.json +1 -1
- package/src/commands/dev.mjs +34 -3
- package/src/update-check.mjs +10 -6
package/README.md
CHANGED
|
@@ -73,4 +73,4 @@ A clean short name (`staff`, `dev`, `test-7`) becomes a readable `credentials.<n
|
|
|
73
73
|
|
|
74
74
|
## Design notes
|
|
75
75
|
|
|
76
|
-
Dependency-free by design (global `fetch` + `git` + the system `tar`), so `npm i -g @tokenoftrust/cli` stays light. `tot dev` is the only command that pulls in the storefront runner: for a standalone checkout it downloads the moat-free runner
|
|
76
|
+
Dependency-free by design (global `fetch` + `git` + the system `tar`), so `npm i -g @tokenoftrust/cli` stays light. `tot dev` is the only command that pulls in the storefront runner: for a standalone checkout it downloads the moat-free runner once per version — from the public npm package `@tokenoftrust/storefront-runner`, after the entitlement-gated `dev_renderer_artifact` answers `use_npm` (its artifact store is not kept in step with npm) — to `~/.tot/cache/renderer/`, `pnpm install`s it there (via corepack — no separate pnpm install needed), and reuses that cache on every later run. See `src/` for the small modules: `context.mjs` (detection), `mcp.mjs` (transport), `auth.mjs` (the identity seam), `commands/`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/cli",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.8",
|
|
4
4
|
"description": "Token of Trust developer CLI — clone 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
|
@@ -185,7 +185,8 @@ async function runStandalone(workspace, args, ctx) {
|
|
|
185
185
|
// Entitled artifact unavailable — stay NATIVE on the public npm runner
|
|
186
186
|
// (@tokenoftrust/storefront-runner, the SAME renderer bits), so
|
|
187
187
|
try {
|
|
188
|
-
|
|
188
|
+
const notice = artifactFallbackNotice(e);
|
|
189
|
+
if (notice) console.error(notice);
|
|
189
190
|
return await runNativePublic(workspace, args, ctx);
|
|
190
191
|
} catch (e2) {
|
|
191
192
|
console.error(formatError(e2));
|
|
@@ -284,7 +285,31 @@ function runMonorepo(ctx, argv) {
|
|
|
284
285
|
* specifically and falls back to Docker instead of hard-failing. Exported so
|
|
285
286
|
* `tot start` can catch it too and fall back the same way.
|
|
286
287
|
*/
|
|
287
|
-
export class NativeArtifactUnavailableError extends Error {
|
|
288
|
+
export class NativeArtifactUnavailableError extends Error {
|
|
289
|
+
/** @param {string} message @param {{ expected?: boolean }} [opts] */
|
|
290
|
+
constructor(message, { expected = false } = {}) {
|
|
291
|
+
super(message);
|
|
292
|
+
// True when the MCP answered that npm is the renderer source: the normal
|
|
293
|
+
// fallback, not a fault, so it is not reported to the developer.
|
|
294
|
+
this.expected = expected;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// dev_renderer_artifact statuses meaning "the artifact store holds no current
|
|
299
|
+
// runner — install it from npm". `use_npm` is the current non-error answer;
|
|
300
|
+
// `stale_artifact` / `not_found` are the error-shaped answers older servers send.
|
|
301
|
+
const USE_NPM_STATUSES = new Set(["use_npm", "stale_artifact", "not_found"]);
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* The line `tot dev` prints when it falls back from the entitled artifact to the
|
|
305
|
+
* public npm runner, or null when the fallback is the expected path.
|
|
306
|
+
* @param {NativeArtifactUnavailableError} e
|
|
307
|
+
* @returns {string|null}
|
|
308
|
+
*/
|
|
309
|
+
export function artifactFallbackNotice(e) {
|
|
310
|
+
if (e.expected) return null;
|
|
311
|
+
return `~ couldn't set up your store preview the usual way (${e.message}) — using the public preview engine instead.`;
|
|
312
|
+
}
|
|
288
313
|
|
|
289
314
|
/**
|
|
290
315
|
* The local landing URL, shared by the native and Docker paths. The store's path is its canonical
|
|
@@ -724,12 +749,18 @@ export async function ensureRendererArtifact(args, { client: providedClient } =
|
|
|
724
749
|
await establishSession(client, { env: process.env });
|
|
725
750
|
}
|
|
726
751
|
const res = await client.callTool("dev_renderer_artifact", {});
|
|
752
|
+
if (USE_NPM_STATUSES.has(res?.status)) {
|
|
753
|
+
throw new NativeArtifactUnavailableError(res.message || "the renderer is served from npm", { expected: true });
|
|
754
|
+
}
|
|
727
755
|
if (!res?.url || !res?.version) {
|
|
728
756
|
throw new Error(res?.error || "no renderer-artifact URL returned");
|
|
729
757
|
}
|
|
730
758
|
credential = res;
|
|
731
759
|
} catch (e) {
|
|
732
|
-
|
|
760
|
+
if (e instanceof NativeArtifactUnavailableError) throw e;
|
|
761
|
+
throw new NativeArtifactUnavailableError(String(e?.message || e), {
|
|
762
|
+
expected: USE_NPM_STATUSES.has(e?.diagnostic?.serverStatus),
|
|
763
|
+
});
|
|
733
764
|
}
|
|
734
765
|
|
|
735
766
|
try {
|
package/src/update-check.mjs
CHANGED
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
* result (instant, no network on the hot path); the registry refresh happens in a
|
|
22
22
|
* DETACHED, unref'd child so it can't add latency or hold the process open.
|
|
23
23
|
* • Cached in `~/.tot/update-check.json`; refreshed at most once per CHECK_INTERVAL_MS.
|
|
24
|
-
* •
|
|
25
|
-
* NO_UPDATE_NOTIFIER is set. `TOT_HOME` overrides the home dir (tests).
|
|
24
|
+
* • Printed to stderr whether or not it is a TTY; suppressed in CI or when
|
|
25
|
+
* TOT_NO_UPDATE_CHECK / NO_UPDATE_NOTIFIER is set. `TOT_HOME` overrides the home dir (tests).
|
|
26
26
|
*/
|
|
27
27
|
import { readFileSync, writeFileSync, mkdirSync, renameSync, chmodSync } from "node:fs";
|
|
28
28
|
import { homedir } from "node:os";
|
|
@@ -195,11 +195,15 @@ export function renderNotice(notice, current) {
|
|
|
195
195
|
.join("\n");
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
/**
|
|
199
|
-
|
|
198
|
+
/**
|
|
199
|
+
* Whether we should print a nudge at all in this environment. Deliberately NOT
|
|
200
|
+
* gated on a TTY: agent-driven sessions run `tot` non-interactively, and a stale
|
|
201
|
+
* CLI caps the runner it resolves at its own major.minor. The nudge goes to
|
|
202
|
+
* stderr, so stdout stays parseable.
|
|
203
|
+
*/
|
|
204
|
+
export function shouldShowNudge(env = process.env) {
|
|
200
205
|
if (env.TOT_NO_UPDATE_CHECK || env.NO_UPDATE_NOTIFIER) return false;
|
|
201
206
|
if (env.CI) return false;
|
|
202
|
-
if (!stream || !stream.isTTY) return false;
|
|
203
207
|
return true;
|
|
204
208
|
}
|
|
205
209
|
|
|
@@ -292,7 +296,7 @@ function refreshInBackground(env) {
|
|
|
292
296
|
*/
|
|
293
297
|
export function maybeNotifyUpdate(current, env = process.env, { stream = process.stderr } = {}) {
|
|
294
298
|
try {
|
|
295
|
-
if (shouldShowNudge(env
|
|
299
|
+
if (shouldShowNudge(env)) {
|
|
296
300
|
const notice = updateNotice(current, env);
|
|
297
301
|
if (notice) stream.write(`${renderNotice(notice, current)}\n`);
|
|
298
302
|
}
|