@tokenoftrust/cli 1.2.0 → 1.2.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/cli",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
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/auth.mjs CHANGED
@@ -27,6 +27,7 @@ import {
27
27
  defaultCredentialsPath, readCredentials, writeCredentials, isExpired,
28
28
  } from "./token-store.mjs";
29
29
  import { refreshAccessToken, credentialsFromToken } from "./oauth.mjs";
30
+ import { recordServerPolicy } from "./update-check.mjs";
30
31
 
31
32
  /** Thrown when no provider can authenticate — carries actionable guidance. */
32
33
  export class AuthUnavailableError extends Error {
@@ -60,11 +61,14 @@ export async function resolveSession(client, opts = {}) {
60
61
  { hint: "source apps/storefront/lib/resolve-tot-credentials.sh (from a storefront checkout), or unset --identity to use developer sign-in." },
61
62
  );
62
63
  }
63
- await client.callTool("credential_validate", {
64
+ const validated = await client.callTool("credential_validate", {
64
65
  totApiKey: env.TOT_API_KEY,
65
66
  totSecretKey: env.TOT_SECRET_KEY,
66
67
  appDomain: env.TOT_APP_DOMAIN,
67
68
  });
69
+ // Update-awareness Layer 2: the MCP may attach a version-support policy to the
70
+ // authed response (wire contract: `cliPolicy`). Safe no-op when absent.
71
+ recordServerPolicy(validated?.cliPolicy, env);
68
72
  return { identity: "operator", appDomain: env.TOT_APP_DOMAIN };
69
73
  }
70
74
 
@@ -13,6 +13,7 @@ import { defaultCredentialsPath, readCredentials, isExpired } from "../token-sto
13
13
  import { hasOperatorCreds, resolveDeveloperSession } from "../auth.mjs";
14
14
  import { createMcpClient } from "../mcp.mjs";
15
15
  import { normalizeStores } from "./checkout.mjs";
16
+ import { recordServerPolicy } from "../update-check.mjs";
16
17
 
17
18
  /**
18
19
  * Pure summary of the cached session — no network. Returned for both display and
@@ -56,7 +57,11 @@ export async function run(argv, _ctx) {
56
57
  const client = createMcpClient(status.mcpUrl || env.MCP_BASE_URL || env.TOT_MCP_URL || "https://mcp.tokenoftrust.com");
57
58
  await client.initialize();
58
59
  await resolveDeveloperSession(client, env);
59
- const stores = normalizeStores(await client.callTool("client_list", {}));
60
+ const listResp = await client.callTool("client_list", {});
61
+ // Update-awareness Layer 2: an authed response may carry a version-support
62
+ // policy (wire contract: `cliPolicy`). Safe no-op when absent.
63
+ recordServerPolicy(listResp?.cliPolicy, env);
64
+ const stores = normalizeStores(listResp);
60
65
  if (stores.length) {
61
66
  console.log(` stores you can build on: ${stores.map((s) => s.id).join(", ")}`);
62
67
  } else {
package/src/mcp.mjs CHANGED
@@ -7,10 +7,26 @@
7
7
  * answer as JSON or as an SSE stream, with the session id carried in the
8
8
  * `Mcp-Session-Id` header across calls. Dependency-free (global fetch, Node 20+).
9
9
  */
10
+ import { readFileSync } from "node:fs";
11
+
12
+ // The CLI's REAL version for the MCP handshake — the transmission channel the
13
+ // server-side support policy (update-awareness Layer 2) decides against. Read from
14
+ // our own package.json (same pattern as bin/tot.mjs); best-effort, never throws.
15
+ export const CLI_VERSION = (() => {
16
+ try {
17
+ return (
18
+ JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version ||
19
+ "0.0.0"
20
+ );
21
+ } catch {
22
+ return "0.0.0";
23
+ }
24
+ })();
10
25
 
11
26
  /**
12
27
  * @param {string} baseUrl - MCP base URL; `/mcp` is appended if absent.
13
- * @param {{ token?: string }} [opts] - optional developer OAuth bearer to attach.
28
+ * @param {{ token?: string, clientVersion?: string }} [opts] - optional developer OAuth
29
+ * bearer to attach; `clientVersion` overrides the handshake version (tests).
14
30
  * @returns a small client: { mcpUrl, initialize, callRaw, callTool, sessionId(), setToken }
15
31
  */
16
32
  export function createMcpClient(baseUrl, opts = {}) {
@@ -86,7 +102,9 @@ export function createMcpClient(baseUrl, opts = {}) {
86
102
  }
87
103
 
88
104
  /** Complete the MCP handshake. Call once before any tool call. */
89
- async function initialize(clientInfo = { name: "tot-cli", version: "0.1.0" }) {
105
+ async function initialize(
106
+ clientInfo = { name: "tot-cli", version: opts.clientVersion || CLI_VERSION },
107
+ ) {
90
108
  await callRaw("initialize", {
91
109
  protocolVersion: "2025-06-18",
92
110
  capabilities: {},