@tokenoftrust/cli 1.3.0-rc.2 → 1.3.0-rc.3

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.3.0-rc.2",
3
+ "version": "1.3.0-rc.3",
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",
@@ -205,23 +205,42 @@ async function runNativePublic(workspace, args, ctx) {
205
205
  return bootNative(runnerDir, workspace, port, url, args);
206
206
  }
207
207
 
208
+ /**
209
+ * Read the hosted-activity-bridge credential (minted alongside the invite's
210
+ * browserless `tot login --code` paste — see login.mjs's cacheActivityBridge)
211
+ * and shape it as the two env vars dev-loop-state.mjs's postActivity reads.
212
+ * Returns {} when absent (an older cached session, a bare `tot login`, or the
213
+ * zero-login --sample path) — the local loop runs exactly the same either way,
214
+ * it just has no hosted signal to report. EVERY path that spawns the runner
215
+ * (native monorepo, native standalone, Docker) must thread this in, or the
216
+ * developer's hosted /dev panel never lights up even though they cached a
217
+ * valid bridge credential at login.
218
+ * @param {NodeJS.ProcessEnv} [env]
219
+ * @returns {{TOT_DEV_ACTIVITY_TOKEN?: string, TOT_DEV_ACTIVITY_URL?: string}}
220
+ */
221
+ export function activityBridgeEnv(env = process.env) {
222
+ const creds = readCredentials(defaultCredentialsPath(env));
223
+ if (!creds?.activityToken || !creds?.activityUrl) return {};
224
+ return { TOT_DEV_ACTIVITY_TOKEN: creds.activityToken, TOT_DEV_ACTIVITY_URL: creds.activityUrl };
225
+ }
226
+
227
+ /**
228
+ * Flatten an env object into repeated `-e KEY=VAL` docker-run args. Pure, so the
229
+ * Docker activity-bridge threading is testable without a real Docker daemon.
230
+ * @param {Record<string, string>} env
231
+ * @returns {string[]}
232
+ */
233
+ export function dockerEnvArgs(env) {
234
+ return Object.entries(env).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
235
+ }
236
+
208
237
  function runMonorepo(ctx, argv) {
209
238
  const script = join(ctx.repoRoot, "scripts", "tot-dev.mjs");
210
239
  if (!existsSync(script)) {
211
240
  console.error(`✗ expected the dev runner at ${script} but it's missing.`);
212
241
  return 2;
213
242
  }
214
- // Thread the hosted-activity-bridge credential (if this cached session has one —
215
- // minted alongside the invite's cli-signin-code paste) so the spawned tot-dev.mjs
216
- // can report file-save activity up to the developer's own hosted /dev panel.
217
- // Best-effort: an older cached session (or a bare `tot login`) simply has
218
- // neither field, and the local loop runs exactly as before with no hosted signal.
219
- const creds = readCredentials(defaultCredentialsPath(process.env));
220
- const env = { ...process.env };
221
- if (creds?.activityToken && creds?.activityUrl) {
222
- env.TOT_DEV_ACTIVITY_TOKEN = creds.activityToken;
223
- env.TOT_DEV_ACTIVITY_URL = creds.activityUrl;
224
- }
243
+ const env = { ...process.env, ...activityBridgeEnv() };
225
244
  return new Promise((resolvePromise) => {
226
245
  const child = spawn(process.execPath, [script, ...argv], { stdio: "inherit", env });
227
246
  child.on("exit", (code) => resolvePromise(code ?? 0));
@@ -271,7 +290,9 @@ async function runNative(workspace, args, ctx) {
271
290
  * zero-login sample path (runSample) so both boot identically.
272
291
  */
273
292
  function bootNative(runnerDir, workspace, port, url, args) {
274
- const handle = spawnNativeDev(runnerDir, workspace, port, { stdio: "inherit" });
293
+ // activityBridgeEnv() is a no-op {} for the zero-login sample path (no cached
294
+ // credential exists there) — safe to always thread it through.
295
+ const handle = spawnNativeDev(runnerDir, workspace, port, { stdio: "inherit", env: activityBridgeEnv() });
275
296
 
276
297
  // Auto-open the browser the moment the server answers (D). Non-blocking so
277
298
  // Ctrl-C / logs are unaffected; --no-open suppresses it.
@@ -758,17 +779,19 @@ function runPnpmInstall(runnerDir) {
758
779
  * auto-open-browser logic works unchanged for either runtime. Exported (and
759
780
  * `stdio` overridable) so `tot start` can pipe the logs instead of inheriting.
760
781
  */
761
- export function spawnNativeDev(runnerDir, workspace, port, { stdio = "inherit" } = {}) {
782
+ export function spawnNativeDev(runnerDir, workspace, port, { stdio = "inherit", env = {} } = {}) {
762
783
  const script = join(runnerDir, "scripts", "tot-dev.mjs");
763
784
  // Translate the same "inherit"|"piped" contract spawnDevContainer honors:
764
785
  // "piped" means stdin ignored + stdout/stderr captured so `tot start` can hold
765
786
  // the prompt on stdin and stream the logs after the aha. child_process.spawn
766
787
  // doesn't understand the bare string "piped", so map it to the array here.
767
788
  const stdioArr = stdio === "piped" ? ["ignore", "pipe", "pipe"] : stdio;
789
+ // `env` (e.g. activityBridgeEnv()) merges OVER process.env — {} is a pure
790
+ // passthrough, identical to the old no-env-key behavior.
768
791
  const child = spawn(
769
792
  process.execPath,
770
793
  [script, "--workspace", workspace, "--port", port],
771
- { cwd: runnerDir, stdio: stdioArr },
794
+ { cwd: runnerDir, stdio: stdioArr, env: { ...process.env, ...env } },
772
795
  );
773
796
  const handle = { child, exited: false, done: null };
774
797
  handle.done = new Promise((resolvePromise) => {
@@ -874,6 +897,10 @@ export function buildContainerPlan(workspace, args, _ctx) {
874
897
  "CHOKIDAR_USEPOLLING=1",
875
898
  "-e",
876
899
  "CHOKIDAR_INTERVAL=300",
900
+ // Docker containers don't inherit the host env — thread the activity-bridge
901
+ // credential explicitly (see activityBridgeEnv), or the Docker runtime never
902
+ // reports to the developer's hosted /dev panel even when native would.
903
+ ...dockerEnvArgs(activityBridgeEnv()),
877
904
  image,
878
905
  ];
879
906
 
@@ -60,7 +60,7 @@ import {
60
60
  buildContainerPlan, spawnDevContainer, dockerAvailable, tryStartDocker,
61
61
  resolveDevImage, isPrivateRegistryImage, ensureRegistryLogin,
62
62
  ensureRendererArtifact, ensureSampleRenderer, spawnNativeDev, deriveUrl,
63
- NativeArtifactUnavailableError,
63
+ activityBridgeEnv, NativeArtifactUnavailableError,
64
64
  } from "./dev.mjs";
65
65
  import { scaffoldSample, isSampleCheckout, sampleConfig, SAMPLE_DIR_NAME } from "../sample.mjs";
66
66
  import { IDEAS } from "./ideas.mjs";
@@ -233,7 +233,7 @@ export async function run(argv, ctx) {
233
233
  } else {
234
234
  url = deriveUrl(ctxDev.config || {}, devArgs.port).url;
235
235
  console.log(` → starting dev … ${url}`);
236
- handle = spawnNativeDev(runtime.runnerDir, dir, devArgs.port, { stdio: "piped" });
236
+ handle = spawnNativeDev(runtime.runnerDir, dir, devArgs.port, { stdio: "piped", env: activityBridgeEnv(env) });
237
237
  }
238
238
 
239
239
  const up = await Promise.race([
@@ -14,8 +14,9 @@
14
14
  * to a different one. `activityToken`/`activityUrl` are a SEPARATE credential
15
15
  * (storefront-issued, not MCP OAuth) that `tot login --code` caches when the
16
16
  * invite paste carries it — see commands/login.mjs `cacheActivityBridge` and
17
- * commands/dev.mjs `runMonorepo`, which threads them to the local dev-loop
18
- * process so it can report file saves to the developer's hosted /dev panel.
17
+ * commands/dev.mjs `activityBridgeEnv`, which every runner-spawning path (native
18
+ * monorepo, native standalone, Docker) threads in so the local dev-loop process
19
+ * can report file saves to the developer's hosted /dev panel.
19
20
  * Dependency-free (node:fs/os/path).
20
21
  *
21
22
  * `TOT_HOME` overrides the home dir (used by tests to point at a temp dir).