@tokenoftrust/cli 2.0.27 → 2.0.28
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 +12 -0
- package/package.json +1 -1
- package/src/commands/doctor.mjs +19 -12
- package/src/commands/login.mjs +2 -3
- package/src/platform.mjs +91 -0
package/bin/tot.mjs
CHANGED
|
@@ -27,6 +27,10 @@ import {
|
|
|
27
27
|
recordDiagnostic,
|
|
28
28
|
resetInvocationDiagnostics,
|
|
29
29
|
} from "../src/diagnostics.mjs";
|
|
30
|
+
import {
|
|
31
|
+
nativeWindowsRefuseMessage,
|
|
32
|
+
shouldRefuseNativeWindows,
|
|
33
|
+
} from "../src/platform.mjs";
|
|
30
34
|
|
|
31
35
|
const BUILD_ORDER = ["clone", "validate", "dev", "preview"];
|
|
32
36
|
|
|
@@ -99,6 +103,14 @@ async function dispatch(cmd, rest, ctx) {
|
|
|
99
103
|
return cmd ? 0 : 2;
|
|
100
104
|
}
|
|
101
105
|
|
|
106
|
+
// Native Windows: refuse before login/--device/start burn cycles on a host the
|
|
107
|
+
// local loop cannot run on. doctor/feedback/ideas stay available so the gate
|
|
108
|
+
// itself is discoverable. WSL reports as linux and passes through.
|
|
109
|
+
if (shouldRefuseNativeWindows(cmd)) {
|
|
110
|
+
process.stderr.write(nativeWindowsRefuseMessage(cmd));
|
|
111
|
+
return 2;
|
|
112
|
+
}
|
|
113
|
+
|
|
102
114
|
if (cmd === "start") {
|
|
103
115
|
const { run } = await import("../src/commands/start.mjs");
|
|
104
116
|
return run(rest, ctx);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.28",
|
|
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/doctor.mjs
CHANGED
|
@@ -25,6 +25,11 @@ import { join } from "node:path";
|
|
|
25
25
|
import { hasLegacyOperatorEnv, legacyOperatorEnvAdvisory } from "../auth.mjs";
|
|
26
26
|
import { MIN_NODE, nodeMeetsFloor } from "../ensure-node.mjs";
|
|
27
27
|
import { clientPackages, osLabel } from "../mcp.mjs";
|
|
28
|
+
import {
|
|
29
|
+
isNativeWindows,
|
|
30
|
+
nativeWindowsDetail,
|
|
31
|
+
shouldAttemptDoctorAutoLogin,
|
|
32
|
+
} from "../platform.mjs";
|
|
28
33
|
import { defaultCredentialsPath, readCredentials, isExpired } from "../token-store.mjs";
|
|
29
34
|
import { dockerAvailable, tryStartDocker, RENDERER_CACHE_ROOT, rendererArtifactComplete } from "./dev.mjs";
|
|
30
35
|
import { loginAndCache } from "./login.mjs";
|
|
@@ -68,14 +73,12 @@ export function collectChecks(_ctx, env = process.env) {
|
|
|
68
73
|
|
|
69
74
|
// Native Windows isn't a supported host for the local loop (the runner install
|
|
70
75
|
// + tar extraction assume a POSIX toolchain) — WSL is, and reports as linux
|
|
71
|
-
// here. Say so up front instead of letting `tot
|
|
72
|
-
const nativeWindows =
|
|
76
|
+
// here. Say so up front instead of letting `tot login` / `tot dev` fail opaquely.
|
|
77
|
+
const nativeWindows = isNativeWindows();
|
|
73
78
|
checks.push({
|
|
74
79
|
name: "supported platform",
|
|
75
80
|
pass: !nativeWindows,
|
|
76
|
-
detail: nativeWindows
|
|
77
|
-
? "native Windows isn't supported yet — run tot inside WSL (https://learn.microsoft.com/windows/wsl/install)"
|
|
78
|
-
: "macOS / Linux / WSL",
|
|
81
|
+
detail: nativeWindows ? nativeWindowsDetail() : "macOS / Linux / WSL",
|
|
79
82
|
blocking: true,
|
|
80
83
|
});
|
|
81
84
|
|
|
@@ -178,13 +181,17 @@ async function applyFixes(checks, env) {
|
|
|
178
181
|
|
|
179
182
|
const auth = checks.find((c) => c.name === "auth identity");
|
|
180
183
|
if (auth && !auth.pass) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
console.log("
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
if (!shouldAttemptDoctorAutoLogin()) {
|
|
185
|
+
console.log(` ~ not signed in — skipping auto-login (${nativeWindowsDetail()})`);
|
|
186
|
+
} else {
|
|
187
|
+
const mcpUrl = env.MCP_BASE_URL || env.TOT_MCP_URL || DEFAULT_MCP_URL;
|
|
188
|
+
console.log(" ~ not signed in — opening the browser to sign in…");
|
|
189
|
+
try {
|
|
190
|
+
await loginAndCache(mcpUrl, env, { log: (m) => console.log(` ${m}`) });
|
|
191
|
+
console.log(" ✓ signed in");
|
|
192
|
+
} catch (e) {
|
|
193
|
+
console.log(` ~ couldn't sign in automatically (${e?.message || e}) — run \`tot login\``);
|
|
194
|
+
}
|
|
188
195
|
}
|
|
189
196
|
}
|
|
190
197
|
}
|
package/src/commands/login.mjs
CHANGED
|
@@ -24,6 +24,7 @@ import { defaultCredentialsPath, readCredentials, writeCredentials } from "../to
|
|
|
24
24
|
import { openBrowser } from "../open.mjs";
|
|
25
25
|
import { fail } from "../errors.mjs";
|
|
26
26
|
import { cockpitRecoveryUrl, normalizeEmailHint, redactEmailForHint, emailFromJwt } from "../auth.mjs";
|
|
27
|
+
import { loginFailureNext } from "../platform.mjs";
|
|
27
28
|
import { isInteractive, promptYesNo } from "../prompt.mjs";
|
|
28
29
|
import { versionStamp } from "../mcp.mjs";
|
|
29
30
|
|
|
@@ -293,9 +294,7 @@ export async function run(argv, _ctx) {
|
|
|
293
294
|
console.error(
|
|
294
295
|
fail(
|
|
295
296
|
`sign-in didn't complete: ${e?.message || e}`,
|
|
296
|
-
args.device
|
|
297
|
-
? "re-run `tot login --device` and approve the code."
|
|
298
|
-
: "re-run `tot login` and finish the browser sign-in (approve the request) — or try `tot login --device`.",
|
|
297
|
+
loginFailureNext({ device: args.device }),
|
|
299
298
|
),
|
|
300
299
|
);
|
|
301
300
|
return 1;
|
package/src/platform.mjs
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-platform readiness for the local loop.
|
|
3
|
+
*
|
|
4
|
+
* Native Windows is unsupported (runner install + tar extraction assume a POSIX
|
|
5
|
+
* toolchain). WSL reports as `linux` and is the supported path on a Windows box.
|
|
6
|
+
* Keep the check + copy in ONE place so doctor, the CLI gate, and login recovery
|
|
7
|
+
* hints cannot drift.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const WSL_INSTALL_URL = "https://learn.microsoft.com/windows/wsl/install";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* True when this process is native Windows (not WSL).
|
|
14
|
+
* @param {string} [platform] Node `process.platform` value (defaults to current).
|
|
15
|
+
*/
|
|
16
|
+
export function isNativeWindows(platform = process.platform) {
|
|
17
|
+
return platform === "win32";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* One-line detail used by `tot doctor` and CliError footers.
|
|
22
|
+
* @param {{ url?: string }} [opts]
|
|
23
|
+
*/
|
|
24
|
+
export function nativeWindowsDetail(opts = {}) {
|
|
25
|
+
const url = opts.url ?? WSL_INSTALL_URL;
|
|
26
|
+
return `native Windows isn't supported yet — run tot inside WSL (${url})`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Multi-line refuse message printed before exit. Names the attempted command so
|
|
31
|
+
* a pasted invite (`tot login --code … && tot start`) still points at WSL.
|
|
32
|
+
* @param {string} [command] e.g. "login", "start"
|
|
33
|
+
*/
|
|
34
|
+
export function nativeWindowsRefuseMessage(command) {
|
|
35
|
+
const verb = command ? `tot ${command}` : "tot";
|
|
36
|
+
return (
|
|
37
|
+
`✗ ${nativeWindowsDetail()}\n` +
|
|
38
|
+
` → next: install WSL, open an Ubuntu (or other Linux) terminal, install Node 24 LTS + git there,\n` +
|
|
39
|
+
` then re-run \`${verb}\` inside WSL — don't keep retrying login/--device on native Windows.\n`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Commands that are safe / useful to run on native Windows so the developer can
|
|
45
|
+
* learn the gate (`doctor`) or report friction (`feedback`) without a false start.
|
|
46
|
+
*/
|
|
47
|
+
export const NATIVE_WINDOWS_ALLOWED_COMMANDS = new Set([
|
|
48
|
+
"help",
|
|
49
|
+
"--help",
|
|
50
|
+
"-h",
|
|
51
|
+
"--version",
|
|
52
|
+
"-v",
|
|
53
|
+
"version",
|
|
54
|
+
"doctor",
|
|
55
|
+
"feedback",
|
|
56
|
+
"ideas",
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {string | null | undefined} command
|
|
61
|
+
* @param {string} [platform] Node `process.platform` value (defaults to current).
|
|
62
|
+
* @returns {boolean} true when this command must refuse on native Windows
|
|
63
|
+
*/
|
|
64
|
+
export function shouldRefuseNativeWindows(command, platform = process.platform) {
|
|
65
|
+
if (!isNativeWindows(/** @type {string} */ (platform))) return false;
|
|
66
|
+
const cmd = String(command ?? "").trim();
|
|
67
|
+
if (!cmd) return false; // bare `tot` → help
|
|
68
|
+
return !NATIVE_WINDOWS_ALLOWED_COMMANDS.has(cmd);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Recovery hint after a failed `tot login`. Never steers native Windows at
|
|
73
|
+
* `--device` — that path still can't run the local loop on win32.
|
|
74
|
+
* @param {{ device?: boolean, platform?: string }} [opts]
|
|
75
|
+
*/
|
|
76
|
+
export function loginFailureNext(opts = {}) {
|
|
77
|
+
const platform = /** @type {string} */ (opts.platform ?? process.platform);
|
|
78
|
+
if (isNativeWindows(platform)) return nativeWindowsDetail();
|
|
79
|
+
return opts.device
|
|
80
|
+
? "re-run `tot login --device` and approve the code."
|
|
81
|
+
: "re-run `tot login` and finish the browser sign-in (approve the request) — or try `tot login --device`.";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* `tot doctor --fix` must not open OAuth on native Windows — the session
|
|
86
|
+
* would be unusable for the local loop, and the browser hop burns a cycle.
|
|
87
|
+
* @param {string} [platform] Node `process.platform` value (defaults to current).
|
|
88
|
+
*/
|
|
89
|
+
export function shouldAttemptDoctorAutoLogin(platform = process.platform) {
|
|
90
|
+
return !isNativeWindows(/** @type {string} */ (platform));
|
|
91
|
+
}
|