@tokenoftrust/cli 2.0.18 → 2.0.20
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/clone.mjs +42 -13
- package/src/commands/dev.mjs +35 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.20",
|
|
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/clone.mjs
CHANGED
|
@@ -287,21 +287,26 @@ export async function run(argv, ctx) {
|
|
|
287
287
|
* cloned: boolean, dir: string|null, head: string|null }>}
|
|
288
288
|
*/
|
|
289
289
|
export async function checkoutTenant(client, { tenant, tag = "main", cloneDir = null, redact = (s) => s }) {
|
|
290
|
-
// The switch
|
|
291
|
-
//
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
//
|
|
290
|
+
// The switch CARRIES the best diagnosis but is NOT a precondition, and the difference
|
|
291
|
+
// matters in both directions:
|
|
292
|
+
//
|
|
293
|
+
// - Discarding its refusal (the original behaviour) meant a genuinely unentitled tenant
|
|
294
|
+
// surfaced later as tenant_checkout complaining about your PRIOR active tenant, which
|
|
295
|
+
// reads as a scope-selection slip rather than a missing grant.
|
|
296
|
+
// - Treating it as fatal breaks the STAFF-PREVIEW path, where the refusal is expected:
|
|
297
|
+
// a staff human checking out a merchant tenant under an authorization holds no client
|
|
298
|
+
// grant on it, so client_switch MUST fail while tenant_checkout legitimately succeeds
|
|
299
|
+
// (it takes the tenant as an argument and resolves the app from the authorization).
|
|
300
|
+
// `tot git-credential` mints through this same function, so a fatal switch also breaks
|
|
301
|
+
// every fetch and push in such a checkout, not just the initial clone.
|
|
302
|
+
//
|
|
303
|
+
// So: remember it, proceed, and surface it only if the checkout ALSO fails — at which
|
|
304
|
+
// point it is the more specific of the two errors.
|
|
305
|
+
let switchRefusal = null;
|
|
296
306
|
try {
|
|
297
307
|
await client.callTool("client_switch", { tenant });
|
|
298
308
|
} catch (e) {
|
|
299
|
-
|
|
300
|
-
next:
|
|
301
|
-
"confirm you're entitled to this store — `tot grants` lists what your session can " +
|
|
302
|
-
"act on, and `tot login` refreshes a grant issued after you signed in",
|
|
303
|
-
cause: e,
|
|
304
|
-
});
|
|
309
|
+
switchRefusal = e;
|
|
305
310
|
}
|
|
306
311
|
// vc-app-binding safety-net (08-18, §5): ensure THIS developer is bound to the
|
|
307
312
|
// storefront version-control app BEFORE checkout, so tenant_checkout can resolve
|
|
@@ -319,13 +324,37 @@ export async function checkoutTenant(client, { tenant, tag = "main", cloneDir =
|
|
|
319
324
|
} catch {
|
|
320
325
|
/* fail-open — see above */
|
|
321
326
|
}
|
|
322
|
-
|
|
327
|
+
let checkout;
|
|
328
|
+
try {
|
|
329
|
+
checkout = await client.callTool("tenant_checkout", { tenant, tag });
|
|
330
|
+
} catch (e) {
|
|
331
|
+
// Both failed: the switch's refusal names the cause more precisely than a thrown
|
|
332
|
+
// checkout, so lead with it.
|
|
333
|
+
if (switchRefusal) {
|
|
334
|
+
throw new CliError(redact(String(switchRefusal?.message || switchRefusal)), {
|
|
335
|
+
next:
|
|
336
|
+
"confirm you're entitled to this store — `tot grants` lists what your session can " +
|
|
337
|
+
"act on, and `tot login` refreshes a grant issued after you signed in",
|
|
338
|
+
cause: switchRefusal,
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
throw e;
|
|
342
|
+
}
|
|
323
343
|
|
|
324
344
|
// A non-checkout result (not provisioned / not entitled / failed) must surface
|
|
325
345
|
// the MCP's human message + a concrete next step, NEVER a raw JSON.stringify
|
|
326
346
|
// dump (James's 2026-07-19 first-experience failure).
|
|
327
347
|
const err = checkoutError(checkout);
|
|
328
348
|
if (err) {
|
|
349
|
+
// Same precedence: an unentitled tenant is better explained by the switch.
|
|
350
|
+
if (switchRefusal) {
|
|
351
|
+
throw new CliError(redact(String(switchRefusal?.message || switchRefusal)), {
|
|
352
|
+
next:
|
|
353
|
+
"confirm you're entitled to this store — `tot grants` lists what your session can " +
|
|
354
|
+
"act on, and `tot login` refreshes a grant issued after you signed in",
|
|
355
|
+
cause: switchRefusal,
|
|
356
|
+
});
|
|
357
|
+
}
|
|
329
358
|
throw new CliError(redact(err.message), { next: err.next });
|
|
330
359
|
}
|
|
331
360
|
const gitRemote = checkout.gitRemote;
|
package/src/commands/dev.mjs
CHANGED
|
@@ -66,7 +66,7 @@ export function parseArgs(argv) {
|
|
|
66
66
|
const a = {
|
|
67
67
|
workspace: null, port: "4321", mcp: null,
|
|
68
68
|
noLogin: false, noOpen: false, sample: false, help: false,
|
|
69
|
-
rendererVersion: null,
|
|
69
|
+
rendererVersion: null, resetCache: false,
|
|
70
70
|
};
|
|
71
71
|
for (let i = 0; i < argv.length; i++) {
|
|
72
72
|
const t = argv[i];
|
|
@@ -77,12 +77,34 @@ export function parseArgs(argv) {
|
|
|
77
77
|
else if (t === "--no-open") a.noOpen = true;
|
|
78
78
|
else if (t === "--sample") a.sample = true;
|
|
79
79
|
else if (t === "--renderer-version") a.rendererVersion = argv[++i];
|
|
80
|
+
else if (t === "--reset-cache") a.resetCache = true;
|
|
80
81
|
else if (t === "--help" || t === "-h") a.help = true;
|
|
81
82
|
}
|
|
82
83
|
return a;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Delete the cached preview engines so the next run downloads and installs fresh.
|
|
88
|
+
*
|
|
89
|
+
* The recovery path this replaces was "hand-delete a directory under ~/.tot/cache" —
|
|
90
|
+
* which agent guidance forbids and no developer should have to know
|
|
91
|
+
* (fb-1789008798249-sc4tgy: the reporter had no way back to a working dev loop
|
|
92
|
+
* without it). A first-class flag makes the supported recovery discoverable in
|
|
93
|
+
* `tot dev --help`.
|
|
94
|
+
*
|
|
95
|
+
* Scoped deliberately to the renderer cache: it is a pure download+install artifact,
|
|
96
|
+
* rebuilt on demand, so removing it can only cost time. It never touches the
|
|
97
|
+
* tenant checkout, the login session, or anything else under ~/.tot.
|
|
98
|
+
* @param {{cacheRoot?: string, rm?: (p: string, o: object) => void}} [deps]
|
|
99
|
+
* @returns {{removed: boolean, path: string}}
|
|
100
|
+
*/
|
|
101
|
+
export function resetRendererCache({ cacheRoot = RENDERER_CACHE_ROOT, rm = rmSync } = {}) {
|
|
102
|
+
const existed = existsSync(cacheRoot);
|
|
103
|
+
rm(cacheRoot, { recursive: true, force: true });
|
|
104
|
+
return { removed: existed, path: cacheRoot };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const USAGE = `tot dev — run your store locally with save→reload
|
|
86
108
|
|
|
87
109
|
tot dev <tenant> (in the monorepo) run tenants/<tenant>/
|
|
88
110
|
tot dev (in a checkout) run this store natively (no Docker)
|
|
@@ -91,6 +113,7 @@ const USAGE = `tot dev — run your store locally with save→reload
|
|
|
91
113
|
tot dev --workspace <dir> run a specific checkout directory
|
|
92
114
|
tot dev --port <n> host port (default 4321)
|
|
93
115
|
tot dev --no-open don't auto-open the browser when the server is up
|
|
116
|
+
tot dev --reset-cache delete the downloaded preview engines and re-fetch
|
|
94
117
|
|
|
95
118
|
Edit content/*.html or the theme + save → the browser reloads. Private local
|
|
96
119
|
preview — nothing is published. Prerequisites: Node.js and an invite (or just
|
|
@@ -104,6 +127,16 @@ export async function run(argv, ctx) {
|
|
|
104
127
|
return 0;
|
|
105
128
|
}
|
|
106
129
|
|
|
130
|
+
// Before anything else, so a wedged cache cannot break the very run meant to clear
|
|
131
|
+
// it. Then fall through and start normally: the flag is a modifier, not a separate
|
|
132
|
+
// command, because "clear it and go" is what a stuck developer actually wants.
|
|
133
|
+
if (args.resetCache) {
|
|
134
|
+
const { removed, path } = resetRendererCache();
|
|
135
|
+
console.error(removed
|
|
136
|
+
? `~ cleared the preview-engine cache (${path}) — this run re-downloads it.`
|
|
137
|
+
: `~ no preview-engine cache to clear (${path}).`);
|
|
138
|
+
}
|
|
139
|
+
|
|
107
140
|
// Resolve a free port up front so the URL we derive/open/print matches the port
|
|
108
141
|
// the runner actually binds — Vite's strictPort is off, so a busy default would
|
|
109
142
|
// silently drift and strand the browser/liveness poll on the wrong port. No-op
|