@vincentt-xr/cli 0.5.1 → 0.7.0

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.
@@ -139,6 +139,18 @@ export declare function hardMaxWarning(clockTime: string, minutesLeft: number):
139
139
  export declare function hardMaxReached(): string[];
140
140
  /** c. Superseded — the terminal that LOST. */
141
141
  export declare function supersededLoser(): string[];
142
+ /**
143
+ * Re-running `vincentt preview` on a folder that already has one attaches to it
144
+ * rather than minting a second — but a caller who is not SHOWN the link cannot
145
+ * tell the difference between "attached" and "failed to give me a URL". The
146
+ * reported behavior was an agent re-running preview until it saw a link, and
147
+ * each of those re-runs superseded the previous session: the link really did
148
+ * keep changing, because the attach never printed one.
149
+ *
150
+ * The URL renders bare on its own line, matching the start block, so anything
151
+ * scraping for a link finds it in the same shape either way.
152
+ */
153
+ export declare function attachedToRunning(url: string, expiresAt?: string): string[];
142
154
  /**
143
155
  * c. Superseded — the terminal that WON. This sits ABOVE the `✓ Preview is live`
144
156
  * block so the consequence is read before the URL is copied.
@@ -299,6 +299,28 @@ export function supersededLoser() {
299
299
  "",
300
300
  ];
301
301
  }
302
+ /**
303
+ * Re-running `vincentt preview` on a folder that already has one attaches to it
304
+ * rather than minting a second — but a caller who is not SHOWN the link cannot
305
+ * tell the difference between "attached" and "failed to give me a URL". The
306
+ * reported behavior was an agent re-running preview until it saw a link, and
307
+ * each of those re-runs superseded the previous session: the link really did
308
+ * keep changing, because the attach never printed one.
309
+ *
310
+ * The URL renders bare on its own line, matching the start block, so anything
311
+ * scraping for a link finds it in the same shape either way.
312
+ */
313
+ export function attachedToRunning(url, expiresAt) {
314
+ const lines = ["", "→ A preview is already running for this folder.", "", url, ""];
315
+ // Stated only when known: a marker written by an older CLI has no expiry, and
316
+ // inventing one would be the over-claim this copy exists to avoid.
317
+ if (expiresAt !== undefined) {
318
+ lines.push(` This link is good until ${expiresAt}.`);
319
+ }
320
+ lines.push(" Start a fresh one: vincentt preview --restart");
321
+ lines.push("");
322
+ return lines;
323
+ }
302
324
  /**
303
325
  * c. Superseded — the terminal that WON. This sits ABOVE the `✓ Preview is live`
304
326
  * block so the consequence is read before the URL is copied.
@@ -33,6 +33,19 @@ export type PreviewEndReason = "stopped"
33
33
  export interface StartPreviewOptions {
34
34
  /** Project directory — its .vincentt binding + dev script drive the preview. */
35
35
  projectCwd: string;
36
+ /**
37
+ * The directory holding the binding — the tree's IDENTITY, as distinct from
38
+ * the directory the dev server runs in.
39
+ *
40
+ * These differ whenever a creator runs `vincentt preview` from a subdirectory
41
+ * of a bound repo: `locateProjectBinding` walks up to find the binding, so the
42
+ * same project resolves from `apps/web/` and from the repo root. Keying the
43
+ * one-session-per-tree rule off the raw cwd made those two spellings two
44
+ * trees, which is precisely what `workingTreeKey` normalizes symlinks and
45
+ * relative paths to prevent. Defaults to projectCwd when the caller has not
46
+ * located a binding.
47
+ */
48
+ projectRoot?: string;
36
49
  /** The API host + PAT. Resolved by the caller so the runner makes no policy. */
37
50
  config: ResolvedConfig;
38
51
  projectId: string;
@@ -22,7 +22,7 @@ import { getFreePort, isPortListening, waitForApp } from "./net.js";
22
22
  import { endPreviewSession, heartbeatPreviewSession, mintPreviewSession, workingTreeKey, PreviewEndedError, } from "./api.js";
23
23
  import { ProjectUnreachableError } from "../lib/backend.js";
24
24
  export async function startPreview(opts) {
25
- const { projectCwd, config, projectId, harnessPath = "/__harness", devCommand = ["npm", "run", "dev"], appStdio = "ignore", appReadyTimeoutMs = 8_000, onLog = () => undefined, fetchImpl = fetch, } = opts;
25
+ const { projectCwd, projectRoot = projectCwd, config, projectId, harnessPath = "/__harness", devCommand = ["npm", "run", "dev"], appStdio = "ignore", appReadyTimeoutMs = 8_000, onLog = () => undefined, fetchImpl = fetch, } = opts;
26
26
  const appPort = opts.appPort ?? 5173;
27
27
  const relayPort = opts.relayPort ?? (await getFreePort());
28
28
  const frontPort = opts.frontPort ?? (await getFreePort());
@@ -56,7 +56,9 @@ export async function startPreview(opts) {
56
56
  // The MINT comes first. Everything below it costs the creator a dev-server
57
57
  // start and a port; if the mint is going to fail — rate limit, revoked
58
58
  // membership, no binding — it should fail before any of that happens.
59
- const key = await workingTreeKey(projectCwd);
59
+ // Keyed on the tree's identity, not the folder the command was typed in:
60
+ // the supersede rule must see one tree however the creator addressed it.
61
+ const key = await workingTreeKey(projectRoot);
60
62
  minted = await mintPreviewSession(config, projectId, key, fetchImpl);
61
63
  if (reuseApp) {
62
64
  onLog(`reusing the dev server already on :${appPort}`);
@@ -73,7 +75,10 @@ export async function startPreview(opts) {
73
75
  relay = startRelay({
74
76
  port: relayPort,
75
77
  path: harnessPath,
76
- projectDir: projectCwd,
78
+ // Annotations land beside the binding, so `vincentt feedback` finds them
79
+ // from anywhere in the tree rather than only from the folder that started
80
+ // the preview.
81
+ projectDir: projectRoot,
77
82
  onLog: (m) => onLog(`[relay] ${m}`),
78
83
  onEvents: opts.onEvents,
79
84
  onAttribute: opts.onAttribute,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincentt-xr/cli",
3
- "version": "0.5.1",
3
+ "version": "0.7.0",
4
4
  "description": "Vincentt CLI — the vincentt command-line dev loop (login, create, publish, preview, diagnostics, feedback, relay)",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",