@tokenoftrust/cli 1.2.2 → 1.2.4
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/bin/tot.mjs +1 -5
- package/package.json +1 -2
- package/src/commands/checkout.mjs +1 -1
- package/src/commands/dev.mjs +64 -14
- package/src/commands/start.mjs +27 -20
- package/src/commands/submit.mjs +4 -5
- package/src/sample.mjs +6 -1
- package/template/sample-store/content/chrome.html +0 -152
- package/template/sample-store/content/chrome.json +0 -94
- package/template/sample-store/content/home.html +0 -194
- package/template/sample-store/content/home.json +0 -50
- package/template/sample-store/content/pages/about.json +0 -10
- package/template/sample-store/content/pages/privacy.json +0 -6
- package/template/sample-store/content/pages/shipping-returns.json +0 -6
- package/template/sample-store/content/pages-html/blogs/news.html +0 -68
- package/template/sample-store/content/pages-html/pages/about-us.html +0 -95
- package/template/sample-store/content/pages-html/pages/contact-us.html +0 -68
- package/template/sample-store/content/pages-html/pages/privacy-policy.html +0 -65
- package/template/sample-store/content/pages-html/pages/shipping-returns.html +0 -77
- package/template/sample-store/content/themes/giant-navy.json +0 -73
- package/template/sample-store/public/img/hero-suicide-bunny.jpg +0 -0
- package/template/sample-store/public/img/hero.webp +0 -0
- package/template/sample-store/public/img/og.jpg +0 -0
- package/template/sample-store/public/logo-wordmark.png +0 -0
- package/template/sample-store/public/pages/home.css +0 -120
- package/template/sample-store/public/pages/mkt.css +0 -185
- package/template/sample-store/public/pages/page.css +0 -155
- package/template/sample-store/public/themes/giant-navy.css +0 -76
- package/template/sample-store/theme.json +0 -39
package/bin/tot.mjs
CHANGED
|
@@ -5,14 +5,12 @@
|
|
|
5
5
|
* One command a developer learns to go from an invite to a running store:
|
|
6
6
|
*
|
|
7
7
|
* tot start invite → running store in one command ← built (orchestrates the below, value-first)
|
|
8
|
-
* tot start --sample FREE local preview — no login, no MCP ← built (zero-login quickstart; MCP is the upsell)
|
|
9
8
|
* tot login sign in to Token of Trust (OAuth) ← built (MCP OAuth PKCE loopback; caches ~/.tot/credentials.json)
|
|
10
9
|
* tot logout sign out (clear the cached session) ← built (deletes ~/.tot/credentials.json; local-only, no server revoke)
|
|
11
10
|
* tot whoami who you're signed in as ← built
|
|
12
11
|
* tot checkout [<tenant>] clone a store you can build on ← built
|
|
13
12
|
* tot validate lint your store before you submit ← built
|
|
14
13
|
* tot dev run your store locally with save→reload ← built (monorepo: host astro; standalone: runs the published runner image)
|
|
15
|
-
* tot dev --sample run a FREE bundled sample store locally ← built (zero-login, no MCP; compliance rendering still shows)
|
|
16
14
|
* tot submit submit your store for preview ← built (validate + push preview ref; MCP preview_status read-back)
|
|
17
15
|
* tot doctor check this machine is ready
|
|
18
16
|
* tot ideas copy-paste AI prompts that reliably wow
|
|
@@ -24,7 +22,7 @@
|
|
|
24
22
|
* from anywhere else. Every command receives the detected context.
|
|
25
23
|
*
|
|
26
24
|
* This package is `@tokenoftrust/cli` (bin `tot`). Its heaviest command, `tot dev`,
|
|
27
|
-
*
|
|
25
|
+
* fetches the published storefront runner; `tot checkout/validate/submit` are
|
|
28
26
|
* pure Node. Dependency-free by design so `npm i -g @tokenoftrust/cli` stays light.
|
|
29
27
|
*/
|
|
30
28
|
import { readFileSync } from "node:fs";
|
|
@@ -49,14 +47,12 @@ function usage() {
|
|
|
49
47
|
tot — Token of Trust developer CLI
|
|
50
48
|
|
|
51
49
|
tot start invite → running store in one command (start here)
|
|
52
|
-
tot start --sample free local preview — no login, no account needed
|
|
53
50
|
tot login sign in to Token of Trust
|
|
54
51
|
tot logout sign out (clear the cached session)
|
|
55
52
|
tot whoami show who you're signed in as
|
|
56
53
|
tot checkout [<tenant>] clone a store you can build on
|
|
57
54
|
tot validate lint your store before you submit
|
|
58
55
|
tot dev run your store locally with save→reload
|
|
59
|
-
tot dev --sample run a free bundled sample store (no login, no MCP)
|
|
60
56
|
tot submit submit your store for preview
|
|
61
57
|
tot doctor check this machine is ready
|
|
62
58
|
tot ideas copy-paste AI prompts that reliably wow
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.4",
|
|
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",
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
"files": [
|
|
26
26
|
"bin",
|
|
27
27
|
"src",
|
|
28
|
-
"template",
|
|
29
28
|
"README.md",
|
|
30
29
|
"LICENSE"
|
|
31
30
|
],
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* `tot` performs NO privileged forge work itself — the MCP owns that.
|
|
14
14
|
*
|
|
15
15
|
* Auth is resolved through src/auth.mjs: operator creds (our dogfooding / CI) or
|
|
16
|
-
* the developer's own ToT identity
|
|
16
|
+
* the developer's own ToT identity. This command doesn't care
|
|
17
17
|
* which — it just needs a validated session.
|
|
18
18
|
*
|
|
19
19
|
* Dependency-free (global fetch + `git` via child_process).
|
package/src/commands/dev.mjs
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* monorepo or --workspace graft mode). Fast host loop for platform devs.
|
|
9
9
|
*
|
|
10
10
|
* checkout — a standalone tenant checkout has no runner. `tot dev` DOWNLOADS the
|
|
11
|
-
* published,
|
|
11
|
+
* published, RUNNER ARTIFACT (a plain tarball — the exact
|
|
12
12
|
* same tree Docker used to bake into the image, see
|
|
13
13
|
* scripts/build/build-runner.mjs) and runs it NATIVELY: no Docker, no
|
|
14
14
|
* container. Cached once per version under ~/.tot/cache/renderer/, so
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
resolveRendererSource as resolveLocalRendererSource, SAMPLE_DIR_NAME,
|
|
49
49
|
} from "../sample.mjs";
|
|
50
50
|
|
|
51
|
-
/** The published
|
|
51
|
+
/** The published runner image (--docker fallback). Override with --image / TOT_DEV_IMAGE. */
|
|
52
52
|
const DEFAULT_DEV_IMAGE =
|
|
53
53
|
"242086487598.dkr.ecr.us-east-1.amazonaws.com/tot-dev:latest";
|
|
54
54
|
const DEFAULT_MCP_URL = "https://mcp.tokenoftrust.com";
|
|
@@ -147,16 +147,56 @@ async function runStandalone(workspace, args, ctx) {
|
|
|
147
147
|
return await runNative(workspace, args, ctx);
|
|
148
148
|
} catch (e) {
|
|
149
149
|
if (e instanceof NativeArtifactUnavailableError) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
// Entitled artifact unavailable — stay NATIVE on the public npm runner
|
|
151
|
+
// (@tokenoftrust/storefront-runner, the SAME renderer bits), so
|
|
152
|
+
// `tot dev` never needs Docker just because dev_renderer_artifact isn't
|
|
153
|
+
// configured. Docker is the last resort only if the public runner is also
|
|
154
|
+
// unreachable (offline).
|
|
155
|
+
try {
|
|
156
|
+
console.error(`~ entitled renderer unavailable (${e.message}) — using the public runner (no Docker).`);
|
|
157
|
+
return await runNativePublic(workspace, args, ctx);
|
|
158
|
+
} catch (e2) {
|
|
159
|
+
if (e2 instanceof NativeArtifactUnavailableError) {
|
|
160
|
+
console.error(`~ public runner unavailable (${e2.message}) — falling back to the Docker runner.`);
|
|
161
|
+
return runContainer(workspace, args, ctx);
|
|
162
|
+
}
|
|
163
|
+
console.error(formatError(e2));
|
|
164
|
+
return e2 instanceof CliError ? (e2.exitCode ?? 2) : 2;
|
|
165
|
+
}
|
|
154
166
|
}
|
|
155
167
|
console.error(formatError(e));
|
|
156
168
|
return e instanceof CliError ? (e.exitCode ?? 2) : 2;
|
|
157
169
|
}
|
|
158
170
|
}
|
|
159
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Native boot against the PUBLIC/local renderer (no MCP, no
|
|
174
|
+
* entitlement) — the fallback for a standalone checkout when the entitled
|
|
175
|
+
* artifact isn't available. Mirrors runNative but resolves the renderer via
|
|
176
|
+
* ensureSampleRenderer (env override → cached runner → in-tree monorepo →
|
|
177
|
+
* public npm), which throws NativeArtifactUnavailableError when even the public
|
|
178
|
+
* runner can't be fetched (offline) so the caller can drop to Docker.
|
|
179
|
+
*/
|
|
180
|
+
async function runNativePublic(workspace, args, ctx) {
|
|
181
|
+
const cfg = readWorkspaceConfig(workspace);
|
|
182
|
+
if (!cfg) {
|
|
183
|
+
throw new CliError(`${workspace} isn't a tenant checkout (no readable .tot/config.json)`, {
|
|
184
|
+
next: "tot checkout <tenant> --clone <dir> (produces a runnable checkout)",
|
|
185
|
+
exitCode: 2,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
const port = String(args.port || "4321");
|
|
189
|
+
const { url } = deriveUrl(cfg, port);
|
|
190
|
+
let runnerDir;
|
|
191
|
+
try {
|
|
192
|
+
runnerDir = await ensureSampleRenderer(args, ctx);
|
|
193
|
+
} catch (e) {
|
|
194
|
+
throw new NativeArtifactUnavailableError(String(e?.message || e));
|
|
195
|
+
}
|
|
196
|
+
printDevBanner({ tenant: cfg.tenant || null, url });
|
|
197
|
+
return bootNative(runnerDir, workspace, port, url, args);
|
|
198
|
+
}
|
|
199
|
+
|
|
160
200
|
function runMonorepo(ctx, argv) {
|
|
161
201
|
const script = join(ctx.repoRoot, "scripts", "tot-dev.mjs");
|
|
162
202
|
if (!existsSync(script)) {
|
|
@@ -187,6 +227,17 @@ export function deriveUrl(cfg, port) {
|
|
|
187
227
|
return { domain, url: `http://localhost:${port}/${domain ? `${domain}/` : ""}` };
|
|
188
228
|
}
|
|
189
229
|
|
|
230
|
+
/**
|
|
231
|
+
* The URL the developer should LAND on: the guided /dev cockpit, not the bare
|
|
232
|
+
* store root. The cockpit embeds a live preview of the store (so they still see
|
|
233
|
+
* it) PLUS the stepper, live Monitor, in-browser file tree/editor/diff, and
|
|
234
|
+
* click-to-source — the whole first-run experience. `deriveUrl().url` (the store
|
|
235
|
+
* root) stays the liveness-poll target (waitForServer); this is what we open + show.
|
|
236
|
+
*/
|
|
237
|
+
export function cockpitUrl(baseUrl) {
|
|
238
|
+
return `${baseUrl}dev`;
|
|
239
|
+
}
|
|
240
|
+
|
|
190
241
|
async function runNative(workspace, args, ctx) {
|
|
191
242
|
const cfg = readWorkspaceConfig(workspace);
|
|
192
243
|
if (!cfg) {
|
|
@@ -222,7 +273,7 @@ function bootNative(runnerDir, workspace, port, url, args) {
|
|
|
222
273
|
.then((up) => {
|
|
223
274
|
if (up && !opened) {
|
|
224
275
|
opened = true;
|
|
225
|
-
openBrowser(url);
|
|
276
|
+
openBrowser(cockpitUrl(url));
|
|
226
277
|
}
|
|
227
278
|
})
|
|
228
279
|
.catch(() => {});
|
|
@@ -274,7 +325,7 @@ export function printSampleBanner({ url }) {
|
|
|
274
325
|
}
|
|
275
326
|
|
|
276
327
|
/**
|
|
277
|
-
* Resolve WHERE to get the
|
|
328
|
+
* Resolve WHERE to get the runner tarball for this run — the seam that
|
|
278
329
|
* splits the entitled and the public (zero-login sample) delivery paths. Returns
|
|
279
330
|
* `{ kind, version, url, strip, cacheKey }`; callers download + extract + install +
|
|
280
331
|
* cache it uniformly (installRunnerTarball).
|
|
@@ -297,7 +348,7 @@ export async function resolveRendererSource(args, { client } = {}) {
|
|
|
297
348
|
}
|
|
298
349
|
|
|
299
350
|
/**
|
|
300
|
-
* PUBLIC, un-entitled source for sample / zero-login mode: the
|
|
351
|
+
* PUBLIC, un-entitled source for sample / zero-login mode: the runner
|
|
301
352
|
* straight from the public npm registry — NO MCP call, NO entitlement. Reads the
|
|
302
353
|
* package's registry metadata (unauthenticated JSON) for the tarball URL + version.
|
|
303
354
|
* Pin with `--renderer-version` / TOT_RUNNER_VERSION, else the `latest` dist-tag.
|
|
@@ -340,7 +391,7 @@ export async function resolveEntitledRendererSource(args, { client: providedClie
|
|
|
340
391
|
}
|
|
341
392
|
|
|
342
393
|
/**
|
|
343
|
-
* Get the
|
|
394
|
+
* Get the renderer artifact for this host — a signed URL from the MCP
|
|
344
395
|
* (dev_renderer_artifact, same entitlement gate as the Docker pull token),
|
|
345
396
|
* downloaded + extracted + `pnpm install`'d ONCE per version under
|
|
346
397
|
* ~/.tot/cache/renderer/<version>/. Later runs of the same version reuse the
|
|
@@ -614,7 +665,7 @@ async function runContainer(workspace, args, ctx) {
|
|
|
614
665
|
.then((up) => {
|
|
615
666
|
if (up && !opened) {
|
|
616
667
|
opened = true;
|
|
617
|
-
openBrowser(plan.url);
|
|
668
|
+
openBrowser(cockpitUrl(plan.url));
|
|
618
669
|
}
|
|
619
670
|
})
|
|
620
671
|
.catch(() => {});
|
|
@@ -691,7 +742,7 @@ export function buildContainerPlan(workspace, args, _ctx) {
|
|
|
691
742
|
/** The crafted "here's your running store" block (Vite/`vercel dev`-grade). */
|
|
692
743
|
export function printDevBanner(plan) {
|
|
693
744
|
console.error(`\n tot dev — ${plan.tenant || "(tenant)"}`);
|
|
694
|
-
console.error(` ➜ Local: ${plan.url}`);
|
|
745
|
+
console.error(` ➜ Local: ${cockpitUrl(plan.url)}`);
|
|
695
746
|
console.error(` ➜ Edit: content/home.html + save → the browser reloads`);
|
|
696
747
|
console.error(` ➜ Private local preview — nothing is published. Ctrl-C to stop.\n`);
|
|
697
748
|
}
|
|
@@ -752,8 +803,7 @@ export function isPrivateRegistryImage(image) {
|
|
|
752
803
|
* Entitlement-gated registry login: ask the MCP for a short-lived pull credential
|
|
753
804
|
* (`dev_image_pull_token`) and `docker login` with it. Best-effort — if the MCP,
|
|
754
805
|
* the session, or the tool isn't available yet, warn softly and continue (an
|
|
755
|
-
* existing `docker login`, or the docker pull error, takes over).
|
|
756
|
-
* half of ~/.tot-mcp/handoffs/2026-07-09-tot-mcp-dev-image-pull-token.md.
|
|
806
|
+
* existing `docker login`, or the docker pull error, takes over).
|
|
757
807
|
*
|
|
758
808
|
* Exported + accepts an already-authenticated `client` (C1: `tot start` reuses
|
|
759
809
|
* its own session and overlaps this with the checkout clone instead of paying
|
package/src/commands/start.mjs
CHANGED
|
@@ -59,7 +59,7 @@ import { normalizeStores, storeListError, checkoutTenant } from "./checkout.mjs"
|
|
|
59
59
|
import {
|
|
60
60
|
buildContainerPlan, spawnDevContainer, dockerAvailable, tryStartDocker,
|
|
61
61
|
resolveDevImage, isPrivateRegistryImage, ensureRegistryLogin,
|
|
62
|
-
ensureRendererArtifact, ensureSampleRenderer, spawnNativeDev, deriveUrl,
|
|
62
|
+
ensureRendererArtifact, ensureSampleRenderer, spawnNativeDev, deriveUrl, cockpitUrl,
|
|
63
63
|
NativeArtifactUnavailableError,
|
|
64
64
|
} from "./dev.mjs";
|
|
65
65
|
import { scaffoldSample, isSampleCheckout, sampleConfig, SAMPLE_DIR_NAME } from "../sample.mjs";
|
|
@@ -93,12 +93,9 @@ const USAGE = `tot start — go from invite to a running store in one command
|
|
|
93
93
|
|
|
94
94
|
tot start preflight → sign in → pick your store → check out →
|
|
95
95
|
run it → open your browser → connect Claude
|
|
96
|
-
tot start --sample the FREE local preview — no login, no MCP, no account:
|
|
97
|
-
scaffold + run a sample store, then offer the MCP upsell
|
|
98
96
|
Options:
|
|
99
97
|
--tenant <id> use this store (skips auto-pick/prompt; remembered for next time)
|
|
100
98
|
--port <n> host port for the dev server (default 4321)
|
|
101
|
-
--sample zero-login free taste (see above); also what a no-session run offers
|
|
102
99
|
--docker use the Docker runner instead of the native runtime (F3
|
|
103
100
|
default); also the automatic fallback if the native
|
|
104
101
|
artifact can't be fetched
|
|
@@ -183,8 +180,8 @@ export async function run(argv, ctx) {
|
|
|
183
180
|
const session = await tryResolveSession(client, env, args);
|
|
184
181
|
if (decideStartMode({ sampleFlag: false, hasSession: !!session }) === "sample") {
|
|
185
182
|
if (!(await confirmSampleFallback(args))) {
|
|
186
|
-
throw new CliError("no Token of Trust session
|
|
187
|
-
next: "tot login (then re-run `tot start`)
|
|
183
|
+
throw new CliError("no Token of Trust session", {
|
|
184
|
+
next: "tot login (then re-run `tot start`)",
|
|
188
185
|
});
|
|
189
186
|
}
|
|
190
187
|
return await runSampleStart(args, ctx, env, startedAt);
|
|
@@ -219,7 +216,7 @@ export async function run(argv, ctx) {
|
|
|
219
216
|
const runtime = { useDocker: args.docker, runnerDir: null };
|
|
220
217
|
await Promise.all([
|
|
221
218
|
ensureCheckout(client, tenant, dir, env),
|
|
222
|
-
prefetchRuntime(client, devArgs, env, runtime),
|
|
219
|
+
prefetchRuntime(client, devArgs, env, runtime, ctx),
|
|
223
220
|
]);
|
|
224
221
|
|
|
225
222
|
// 5. dev — native by default (F3), Docker on --docker or the fallback
|
|
@@ -247,13 +244,13 @@ export async function run(argv, ctx) {
|
|
|
247
244
|
});
|
|
248
245
|
}
|
|
249
246
|
if (!args.noOpen) {
|
|
250
|
-
openBrowser(url);
|
|
247
|
+
openBrowser(cockpitUrl(url));
|
|
251
248
|
console.log(" ✓ opened your browser");
|
|
252
249
|
}
|
|
253
250
|
|
|
254
251
|
// 6. you're live (G) — end at the AI-wow, THEN offer the MCP (C). Print the
|
|
255
252
|
// elapsed time (A3) so the "instant" claim is measured, not just felt.
|
|
256
|
-
printLiveEnding(tenant, url, formatElapsed(Date.now() - startedAt));
|
|
253
|
+
printLiveEnding(tenant, cockpitUrl(url), formatElapsed(Date.now() - startedAt));
|
|
257
254
|
if (!args.noConnect) {
|
|
258
255
|
const yes = args.yes || (await promptYesNo(" Connect Claude for AI editing?", true));
|
|
259
256
|
if (yes) connectClaude();
|
|
@@ -320,12 +317,12 @@ async function runSampleStart(args, ctx, env, startedAt) {
|
|
|
320
317
|
});
|
|
321
318
|
}
|
|
322
319
|
if (!args.noOpen) {
|
|
323
|
-
openBrowser(url);
|
|
320
|
+
openBrowser(cockpitUrl(url));
|
|
324
321
|
console.log(" ✓ opened your browser");
|
|
325
322
|
}
|
|
326
323
|
|
|
327
324
|
// You're live — the FREE preview. End on the MCP upsell (the whole point).
|
|
328
|
-
printSampleLiveEnding(url, formatElapsed(Date.now() - startedAt));
|
|
325
|
+
printSampleLiveEnding(cockpitUrl(url), formatElapsed(Date.now() - startedAt));
|
|
329
326
|
if (!args.noConnect) {
|
|
330
327
|
const yes = args.yes || (await promptYesNo(" Connect the ToT MCP for your real store + AI editing?", true));
|
|
331
328
|
if (yes) connectClaude();
|
|
@@ -418,11 +415,16 @@ async function preflight(ctx, env) {
|
|
|
418
415
|
* Prefetch the runner (C1) so it's overlapped with checkout instead of paid
|
|
419
416
|
* for serially afterward: the native renderer artifact by default (F3 — no
|
|
420
417
|
* Docker prerequisite), or the Docker registry pull credential on --docker.
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
418
|
+
*
|
|
419
|
+
* On a native (entitled-artifact) fetch failure the runtime stays NATIVE: it
|
|
420
|
+
* falls back to the PUBLIC npm runner (@tokenoftrust/storefront-runner) — the
|
|
421
|
+
* SAME renderer bits the entitled artifact ships, just delivered over
|
|
422
|
+
* public npm instead of a signed URL — so `tot dev`/`tot start` never require
|
|
423
|
+
* Docker just because `dev_renderer_artifact` isn't configured on a deployment.
|
|
424
|
+
* Docker is the LAST resort, only when the public runner is also unreachable
|
|
425
|
+
* (offline) — flipping `runtime.useDocker` so the caller's dev step picks it up.
|
|
424
426
|
*/
|
|
425
|
-
async function prefetchRuntime(client, devArgs, env, runtime) {
|
|
427
|
+
async function prefetchRuntime(client, devArgs, env, runtime, ctx) {
|
|
426
428
|
if (runtime.useDocker) {
|
|
427
429
|
await prefetchDockerLogin(client, devArgs, env);
|
|
428
430
|
return;
|
|
@@ -431,9 +433,15 @@ async function prefetchRuntime(client, devArgs, env, runtime) {
|
|
|
431
433
|
runtime.runnerDir = await ensureRendererArtifact(devArgs, { client });
|
|
432
434
|
} catch (e) {
|
|
433
435
|
if (!(e instanceof NativeArtifactUnavailableError)) throw e;
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
436
|
+
// Entitled artifact unavailable — stay native on the public runner (no Docker).
|
|
437
|
+
try {
|
|
438
|
+
console.log(` ~ entitled renderer unavailable (${e.message}) — using the public runner (no Docker).`);
|
|
439
|
+
runtime.runnerDir = await ensureSampleRenderer(devArgs, ctx, { env });
|
|
440
|
+
} catch (e2) {
|
|
441
|
+
console.log(` ~ public runner unavailable (${e2?.message || e2}) — falling back to the Docker runner.`);
|
|
442
|
+
runtime.useDocker = true;
|
|
443
|
+
await prefetchDockerLogin(client, devArgs, env);
|
|
444
|
+
}
|
|
437
445
|
}
|
|
438
446
|
}
|
|
439
447
|
|
|
@@ -493,8 +501,7 @@ function noStoresError({ session, baseUrl, listErr }) {
|
|
|
493
501
|
{
|
|
494
502
|
next:
|
|
495
503
|
"if you were just invited, it may still be propagating — try again in a minute; " +
|
|
496
|
-
"otherwise ask your Token of Trust contact for a store invite (see `tot whoami`),
|
|
497
|
-
"or `tot start --sample` for the free local preview",
|
|
504
|
+
"otherwise ask your Token of Trust contact for a store invite (see `tot whoami`)",
|
|
498
505
|
},
|
|
499
506
|
);
|
|
500
507
|
}
|
package/src/commands/submit.mjs
CHANGED
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
* 3. report back — reconcile result + compliance verdict + the preview URL — from the MCP.
|
|
8
8
|
*
|
|
9
9
|
* This is submit-for-PREVIEW, not ship-to-live (`change_accept` / a future `tot ship`
|
|
10
|
-
* is the separate ship gate). Step 3 calls the MCP `preview_status` read-back
|
|
11
|
-
*
|
|
12
|
-
* just pushed it returns { status, reconcile, compliance, previewUrl } and we poll it
|
|
10
|
+
* is the separate ship gate). Step 3 calls the MCP `preview_status` read-back:
|
|
11
|
+
* given the commit just pushed it returns { status, reconcile, compliance, previewUrl } and we poll it
|
|
13
12
|
* while reconcile is pending. If that tool isn't present (older MCP) the command still
|
|
14
13
|
* validates + pushes and reports "reconcile pending" — degrading visibly, never a crash.
|
|
15
14
|
*
|
|
@@ -231,8 +230,8 @@ const CHECK_GLYPH = { pass: "✓", fail: "✗", warn: "⚠", skip: "~" };
|
|
|
231
230
|
|
|
232
231
|
/**
|
|
233
232
|
* Print one per-rule compliance check: id/label, required-ness, why it didn't
|
|
234
|
-
* pass (detail), and a concrete fix suggestion (hint) when there is one. This
|
|
235
|
-
*
|
|
233
|
+
* pass (detail), and a concrete fix suggestion (hint) when there is one. This
|
|
234
|
+
* beats a bare pass/fail — an agent (or a human) reading `tot submit`
|
|
236
235
|
* output should know exactly what to change and why, with no dashboard round-trip.
|
|
237
236
|
*/
|
|
238
237
|
function reportComplianceCheck(c) {
|
package/src/sample.mjs
CHANGED
|
@@ -110,7 +110,12 @@ export function scaffoldSample(destDir, { force = false, log = () => {} } = {})
|
|
|
110
110
|
|
|
111
111
|
const template = sampleTemplateDir();
|
|
112
112
|
if (!existsSync(template)) {
|
|
113
|
-
|
|
113
|
+
const err = new Error(
|
|
114
|
+
"the sample store isn't available in this release yet — it's coming soon. " +
|
|
115
|
+
"To build a real store now: `tot login --code <invite>` then `tot start`.",
|
|
116
|
+
);
|
|
117
|
+
err.code = "SAMPLE_UNAVAILABLE";
|
|
118
|
+
throw err;
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
mkdirSync(dir, { recursive: true });
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<link rel="icon" type="image/png" href="/tenants/giantvapes/logo-wordmark.png">
|
|
7
|
-
<link rel="stylesheet" href="/tenants/giantvapes/themes/giant-navy.css">
|
|
8
|
-
<link rel="stylesheet" href="/tenants/giantvapes/pages/mkt.css">
|
|
9
|
-
<!--PAGE_HEAD-->
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<a class="skip-link" href="#main">Skip to main content</a>
|
|
13
|
-
|
|
14
|
-
<!-- Top FDA warning bar -->
|
|
15
|
-
<div class="topbar-warning"><p>WARNING: This product contains nicotine. Nicotine is an addictive chemical.</p></div>
|
|
16
|
-
|
|
17
|
-
<!-- Announcement: scrolling marquee -->
|
|
18
|
-
<div class="announce-marquee" aria-label="Free US shipping on orders over $100">
|
|
19
|
-
<div class="announce-marquee__track" aria-hidden="true">
|
|
20
|
-
<span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span>
|
|
21
|
-
<span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span>
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
|
|
25
|
-
<!-- Utility nav -->
|
|
26
|
-
<div class="utility-nav">
|
|
27
|
-
<div class="container">
|
|
28
|
-
<ul>
|
|
29
|
-
<li><a href="/blogs/news">News</a></li>
|
|
30
|
-
<li><a href="/pages/about-us">About</a></li>
|
|
31
|
-
<li><a href="/pages/contact-us">Contact</a></li>
|
|
32
|
-
<li><a href="/pages/faq">FAQ</a></li>
|
|
33
|
-
<li><a href="/pages/order-tracking">Track Order</a></li>
|
|
34
|
-
</ul>
|
|
35
|
-
<div class="utility-nav__right">
|
|
36
|
-
<span class="sel">English</span>
|
|
37
|
-
<span class="sel">United States (USD $)</span>
|
|
38
|
-
<span class="social">
|
|
39
|
-
<a href="https://instagram.com/giantvapes" aria-label="Instagram" rel="noopener"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="1.1"/></svg></a>
|
|
40
|
-
<a href="https://facebook.com/giantvapes" aria-label="Facebook" rel="noopener"><svg viewBox="0 0 24 24"><path d="M14 8h2V5h-2a4 4 0 0 0-4 4v2H8v3h2v6h3v-6h2.2l.8-3H13V9a1 1 0 0 1 1-1z"/></svg></a>
|
|
41
|
-
</span>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
|
|
46
|
-
<!-- Header -->
|
|
47
|
-
<header class="site-header">
|
|
48
|
-
<div class="container header-row">
|
|
49
|
-
<a class="brand" href="/" aria-label="Giant Vapes home"><img src="/tenants/giantvapes/logo-wordmark.png" alt="Giant Vapes" width="200" height="106"></a>
|
|
50
|
-
<form class="header-search" action="/search" method="get" role="search">
|
|
51
|
-
<label class="sr-only" for="hdr-q">Search for anything</label>
|
|
52
|
-
<input id="hdr-q" type="search" name="q" placeholder="Search e-liquids, disposables, hardware" autocomplete="off">
|
|
53
|
-
<button type="submit" aria-label="Search"><svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg></button>
|
|
54
|
-
</form>
|
|
55
|
-
<div class="header-actions">
|
|
56
|
-
<a href="/account" aria-label="Account"><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4.4 3.6-7 8-7s8 2.6 8 7"/></svg></a>
|
|
57
|
-
<a class="cart" href="/cart" aria-label="Cart"><svg viewBox="0 0 24 24"><path d="M6 6h15l-1.5 9h-12z"/><circle cx="9" cy="20" r="1.4"/><circle cx="18" cy="20" r="1.4"/><path d="M6 6L5 3H2"/></svg><span class="count">0</span></a>
|
|
58
|
-
<button class="hamburger" id="hamburger" aria-label="Toggle navigation menu" aria-expanded="false" aria-controls="primaryNav"><span></span><span></span><span></span></button>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
<nav class="primary-nav-bar" aria-label="Primary">
|
|
62
|
-
<div class="container">
|
|
63
|
-
<nav class="primary-nav" id="primaryNav">
|
|
64
|
-
<ul>
|
|
65
|
-
<li><a href="/collections/all">E-Liquid<span class="caret">▾</span></a></li>
|
|
66
|
-
<li><a href="/collections/salt-nic">Salt Nic</a></li>
|
|
67
|
-
<li><a href="/collections/all-disposables">Disposables<span class="caret">▾</span></a></li>
|
|
68
|
-
<li><a href="/collections/vaporesso">Hardware<span class="caret">▾</span></a></li>
|
|
69
|
-
<li><a href="/collections/nicotine-pouches">Nic Pouches</a></li>
|
|
70
|
-
<li><a href="/collections/new-arrivals">New Arrivals</a></li>
|
|
71
|
-
<li><a class="is-flag" href="/collections/clearance">Clearance<span class="new-badge">SALE</span></a></li>
|
|
72
|
-
<li><a href="/collections/all">Brands<span class="caret">▾</span></a></li>
|
|
73
|
-
</ul>
|
|
74
|
-
</nav>
|
|
75
|
-
</div>
|
|
76
|
-
</nav>
|
|
77
|
-
</header>
|
|
78
|
-
|
|
79
|
-
<!--PAGE_BODY-->
|
|
80
|
-
|
|
81
|
-
<!-- Compliance strip -->
|
|
82
|
-
<div class="compliance-strip">
|
|
83
|
-
<div class="container"><p>WARNING: This product contains nicotine. Nicotine is an addictive chemical.</p></div>
|
|
84
|
-
</div>
|
|
85
|
-
|
|
86
|
-
<!-- Footer -->
|
|
87
|
-
<footer class="site-footer">
|
|
88
|
-
<div class="container">
|
|
89
|
-
<div class="footer-grid">
|
|
90
|
-
<div class="footer-brand">
|
|
91
|
-
<img src="/tenants/giantvapes/logo-wordmark.png" alt="Giant Vapes" width="200" height="106">
|
|
92
|
-
<p>Premium e-liquid, salts, and disposables — shipped fast.<br>Serving vapers online since 2013.</p>
|
|
93
|
-
</div>
|
|
94
|
-
<div class="footer-col">
|
|
95
|
-
<h4>Shop</h4>
|
|
96
|
-
<ul>
|
|
97
|
-
<li><a href="/collections/all">E-Liquid</a></li>
|
|
98
|
-
<li><a href="/collections/salt-nic">Salt Nic</a></li>
|
|
99
|
-
<li><a href="/collections/all-disposables">Disposables</a></li>
|
|
100
|
-
<li><a href="/collections/vaporesso">Hardware</a></li>
|
|
101
|
-
<li><a href="/collections/nicotine-pouches">Nic Pouches</a></li>
|
|
102
|
-
<li><a href="/collections/clearance">Clearance</a></li>
|
|
103
|
-
</ul>
|
|
104
|
-
</div>
|
|
105
|
-
<div class="footer-col">
|
|
106
|
-
<h4>Support</h4>
|
|
107
|
-
<ul>
|
|
108
|
-
<li><a href="/search">Search</a></li>
|
|
109
|
-
<li><a href="/pages/about-us">About Us</a></li>
|
|
110
|
-
<li><a href="/pages/contact-us">Contact Us</a></li>
|
|
111
|
-
<li><a href="/pages/faq">FAQ</a></li>
|
|
112
|
-
<li><a href="/pages/order-tracking">Order Tracking</a></li>
|
|
113
|
-
<li><a href="/blogs/news">Blog</a></li>
|
|
114
|
-
</ul>
|
|
115
|
-
</div>
|
|
116
|
-
<div class="footer-col">
|
|
117
|
-
<h4>Company</h4>
|
|
118
|
-
<ul>
|
|
119
|
-
<li><a href="/pages/shipping-returns">Shipping & Returns</a></li>
|
|
120
|
-
<li><a href="/pages/privacy-policy">Privacy Policy</a></li>
|
|
121
|
-
<li><a href="/pages/giant-distribution">Wholesale</a></li>
|
|
122
|
-
</ul>
|
|
123
|
-
<form class="footer-news" action="/api/newsletter" method="post">
|
|
124
|
-
<input type="hidden" name="source" value="footer">
|
|
125
|
-
<label class="sr-only" for="foot-email">Email</label>
|
|
126
|
-
<input id="foot-email" type="email" name="email" placeholder="Email" required>
|
|
127
|
-
<button type="submit" aria-label="Subscribe">→</button>
|
|
128
|
-
</form>
|
|
129
|
-
<div class="pay-badges" aria-label="Accepted payments">
|
|
130
|
-
<span>AMEX</span><span>Discover</span><span>Mastercard</span><span>Visa</span><span>PayPal</span>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
</div>
|
|
134
|
-
<div class="footer-warning">
|
|
135
|
-
<p><strong>WARNING:</strong> This product contains nicotine. Nicotine is an addictive chemical. Products intended for adults of legal smoking age (21+) only.</p>
|
|
136
|
-
</div>
|
|
137
|
-
<div class="footer-bottom">
|
|
138
|
-
<p>© Giant Vapes, LLC. All rights reserved.</p>
|
|
139
|
-
<p>Must be 21 or older to purchase. Not for sale to minors.</p>
|
|
140
|
-
</div>
|
|
141
|
-
</div>
|
|
142
|
-
</footer>
|
|
143
|
-
|
|
144
|
-
<script>
|
|
145
|
-
(function () {
|
|
146
|
-
var burger = document.getElementById('hamburger');
|
|
147
|
-
var nav = document.getElementById('primaryNav');
|
|
148
|
-
if (burger && nav) burger.addEventListener('click', function () { var o = nav.classList.toggle('open'); burger.setAttribute('aria-expanded', o ? 'true' : 'false'); });
|
|
149
|
-
})();
|
|
150
|
-
</script>
|
|
151
|
-
</body>
|
|
152
|
-
</html>
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"announcement": "FREE U.S. Shipping on Orders Over $100!",
|
|
3
|
-
"nav": [
|
|
4
|
-
{
|
|
5
|
-
"label": "E-Liquid",
|
|
6
|
-
"href": "/collections/fruity-e-liquids",
|
|
7
|
-
"children": [
|
|
8
|
-
{
|
|
9
|
-
"label": "Fruity E-Liquids",
|
|
10
|
-
"href": "/collections/fruity-e-liquids"
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"label": "Nicotine Salts",
|
|
14
|
-
"href": "/collections/nicotine-salts"
|
|
15
|
-
}
|
|
16
|
-
]
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"label": "Fruity E-Liquids",
|
|
20
|
-
"href": "/collections/fruity-e-liquids"
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"label": "Nicotine Salts",
|
|
24
|
-
"href": "/collections/nicotine-salts"
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
"label": "Disposables",
|
|
28
|
-
"href": "/collections/all-disposables"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"label": "About",
|
|
32
|
-
"href": "/about"
|
|
33
|
-
}
|
|
34
|
-
],
|
|
35
|
-
"footer": {
|
|
36
|
-
"tagline": "Premium e-liquid, salts, and disposables — shipped fast.",
|
|
37
|
-
"columns": [
|
|
38
|
-
{
|
|
39
|
-
"title": "Shop",
|
|
40
|
-
"links": [
|
|
41
|
-
{
|
|
42
|
-
"label": "Fruity E-Liquids",
|
|
43
|
-
"href": "/collections/fruity-e-liquids"
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"label": "Nicotine Salts",
|
|
47
|
-
"href": "/collections/nicotine-salts"
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"label": "Disposables",
|
|
51
|
-
"href": "/collections/all-disposables"
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"label": "Search",
|
|
55
|
-
"href": "/search"
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
"title": "Company",
|
|
61
|
-
"links": [
|
|
62
|
-
{
|
|
63
|
-
"label": "About",
|
|
64
|
-
"href": "/about"
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"label": "Shipping & Returns",
|
|
68
|
-
"href": "/shipping-returns"
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
"label": "Privacy",
|
|
72
|
-
"href": "/privacy"
|
|
73
|
-
}
|
|
74
|
-
]
|
|
75
|
-
}
|
|
76
|
-
],
|
|
77
|
-
"social": [
|
|
78
|
-
{
|
|
79
|
-
"label": "Instagram",
|
|
80
|
-
"href": "https://instagram.com"
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
"label": "Newsletter",
|
|
84
|
-
"href": "#newsletter"
|
|
85
|
-
}
|
|
86
|
-
]
|
|
87
|
-
},
|
|
88
|
-
"disclaimer": "<p>This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a><p></p>\n<p>Giant Vapes will not be held liable for any injury, damage, or defect, permanent or temporary that may be caused by the improper use of these products. Please have a great understanding of the items you are using and how to store, use and care for your products properly. Terms and Conditions.</p>\n<p><b>WARNING:</b> This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a></p>\n<p>This consumable nicotine product is not eligible for return, refund or exchange.</p>",
|
|
89
|
-
"disclaimers": {
|
|
90
|
-
"Vape Juice": "<p>This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a><p></p>\n<p>Giant Vapes will not be held liable for any injury, damage, or defect, permanent or temporary that may be caused by the improper use of these products. Please have a great understanding of the items you are using and how to store, use and care for your products properly. Terms and Conditions.</p>\n<p><b>WARNING:</b> This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a></p>\n<p>This consumable nicotine product is not eligible for return, refund or exchange.</p>",
|
|
91
|
-
"Nicotine Salt": "<p><b>WARNING: Do not use this product in sub-ohm tanks or with sub-ohm coils.</b> This eliquid contains nicotine salt and has a substantially higher amount of nicotine per milliliter than other eliquids. This eliquid is designed <b>only</b> for use with high-resistance coils (1.0 ohm or higher) and ultra low output/low wattage vaping devices.<p></p>\n<p>This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a><p></p>\n<p>Giant Vapes will not be held liable for any injury, damage, or defect, permanent or temporary that may be caused by the improper use of these products. Please have a great understanding of the items you are using and how to store, use and care for your products properly. Terms and Conditions.</p>\n<p><b>WARNING:</b> This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a></p>\n<p>This consumable nicotine product is not eligible for return, refund or exchange.</p>",
|
|
92
|
-
"Vape Disposable": "<p>There is always risk involved when using tobacco and nicotine products and/or rechargeable batteries, at any time and under any circumstances. Giant Vapes is not held responsible for any damage for any modification of the batteries, chargers, devices and other products that are sold on GiantVapes.com.</p>\n<p>Please Note: There is always risk involved when using rechargeable batteries at anytime and under any circumstances. Giant Vapes, LLC is not held responsible for any damage for any modification of the batteries, chargers, devices and other products that are sold on GiantVapes.com.</p>\n<p>Giant Vapes, LLC will not be held liable for any injury, damage, or defect, permanent or temporary that may be caused by the improper use of a Li-ion (Lithium-ion), LiPo (Lithium-ion Polymer) nor any rechargeable battery/batteries as well as chargers. Please have a great understanding of the batteries/chargers you are using and how to care for them properly. You can see a list of our recommendations for proper handling of rechargeable batteries in our terms and conditions</p>\n<p>This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a><p></p>\n<p>Giant Vapes will not be held liable for any injury, damage, or defect, permanent or temporary that may be caused by the improper use of these products. Please have a great understanding of the items you are using and how to store, use and care for your products properly. Terms and Conditions.</p>\n<p><b>WARNING:</b> This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a></p>"
|
|
93
|
-
}
|
|
94
|
-
}
|