@vincentt-xr/cli 0.15.1 → 0.15.2

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/dist/cli/index.js CHANGED
@@ -21,6 +21,7 @@ import { ensureLoggedIn } from "../login/ensure.js";
21
21
  import { clearMachineToken, loadMachineConfig, locateProjectBinding, resolveConfig, writeDxEnablement, MACHINE_CONFIG_PATH, } from "../shared/config.js";
22
22
  import { fileLocationStore } from "../shared/locationStore.js";
23
23
  import { getMe, listProjects, ProjectUnreachableError } from "../lib/backend.js";
24
+ import { EXIT } from "../lib/exitCodes.js";
24
25
  import { listProjectsCommand } from "../lib/listProjects.js";
25
26
  import { initCommand } from "../lib/initCommand.js";
26
27
  import { linkCommand, printUnreachable, unlinkCommand } from "../lib/projects.js";
@@ -813,7 +814,7 @@ async function feedbackWait(cwd, timeoutMs, verbose) {
813
814
  break;
814
815
  for (const l of feedbackCopy.windowElapsed(timeoutMs))
815
816
  console.error(l);
816
- return 64;
817
+ return EXIT.WINDOW_ELAPSED;
817
818
  }
818
819
  if (result.kind === "closed") {
819
820
  if (handed > 0)
@@ -825,7 +826,7 @@ async function feedbackWait(cwd, timeoutMs, verbose) {
825
826
  console.error(l);
826
827
  }
827
828
  }
828
- return 65;
829
+ return EXIT.CHANNEL_ENDED;
829
830
  }
830
831
  await handOver(cwd, result.annotation);
831
832
  after = result.annotation.seq;
@@ -882,7 +883,7 @@ async function feedbackWatch(cwd, timeoutMs, verbose) {
882
883
  console.error(l);
883
884
  }
884
885
  }
885
- return 65;
886
+ return EXIT.CHANNEL_ENDED;
886
887
  }
887
888
  const a = result.annotation;
888
889
  await handOver(cwd, a);
@@ -1110,7 +1111,7 @@ async function assets() {
1110
1111
  for (const l of unreachableLines("auth", 'vincentt assets search "<what you want>"')) {
1111
1112
  console.error(l);
1112
1113
  }
1113
- process.exitCode = 4;
1114
+ process.exitCode = EXIT.NOT_AUTHENTICATED;
1114
1115
  return;
1115
1116
  }
1116
1117
  const deps = {
@@ -15,6 +15,7 @@
15
15
  * Detection is deliberately loose. A false positive costs a line in a report a
16
16
  * human is already reading; a miss costs a DX gap nobody ever hears about.
17
17
  */
18
+ import { EXIT } from "../lib/exitCodes.js";
18
19
  import { verbOf } from "./skeleton.js";
19
20
  /**
20
21
  * Non-zero exits a verb DEFINES as ordinary outcomes, not failures.
@@ -26,11 +27,19 @@ import { verbOf } from "./skeleton.js";
26
27
  * fight-with-the-tool that never happened, and the nudge narrates the intended
27
28
  * loop as friction — on stderr, which in this loop is a caller's own input.
28
29
  *
30
+ * `create` and `init` exit 3 when the scaffold landed but no account was on the
31
+ * machine to reserve an address. The creator holds a working project, so
32
+ * counting it as a fault would make the nudge narrate a delivered project as a
33
+ * fight with the tool. `LOOPING_VERBS` deliberately does NOT gain these two:
34
+ * re-running create without signing in first IS real repetition.
35
+ *
29
36
  * A verb's neutral exits are ITS OWN. Nothing here generalizes 64/65 across the
30
37
  * CLI; another verb adding a non-zero-but-fine exit adds a row.
31
38
  */
32
39
  const NEUTRAL_EXITS = {
33
- feedback: new Set([64, 65]),
40
+ feedback: new Set([EXIT.WINDOW_ELAPSED, EXIT.CHANNEL_ENDED]),
41
+ create: new Set([EXIT.DELIVERED_NOT_REGISTERED]),
42
+ init: new Set([EXIT.DELIVERED_NOT_REGISTERED]),
34
43
  };
35
44
  /**
36
45
  * Verbs whose contract is "run it again". Repeating them is not a caller failing
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Every exit code the CLI returns. B-F12-1: APPEND-ONLY — a code may be added,
3
+ * an existing code's meaning never changes. Removing or repurposing one breaks
4
+ * grounding that already shipped into a creator's repository and is never read
5
+ * back, so the platform cannot warn about it or repair it.
6
+ */
7
+ export declare const EXIT: {
8
+ /** The command did what it was asked. */
9
+ readonly OK: 0;
10
+ /** The command failed and nothing lasting was produced. */
11
+ readonly FAILED: 1;
12
+ /**
13
+ * The project source was written by this invocation, but no address was
14
+ * reserved: no account on this machine, and no browser to get one. The
15
+ * creator holds a working local project; only registration is deferred.
16
+ */
17
+ readonly DELIVERED_NOT_REGISTERED: 3;
18
+ /** A platform call needed an account and the command did not answer for it. */
19
+ readonly NOT_AUTHENTICATED: 4;
20
+ /** A bounded wait elapsed with nothing handed over. */
21
+ readonly WINDOW_ELAPSED: 64;
22
+ /** The channel ended before anything was handed over. */
23
+ readonly CHANNEL_ENDED: 65;
24
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Every exit code the CLI returns. B-F12-1: APPEND-ONLY — a code may be added,
3
+ * an existing code's meaning never changes. Removing or repurposing one breaks
4
+ * grounding that already shipped into a creator's repository and is never read
5
+ * back, so the platform cannot warn about it or repair it.
6
+ */
7
+ export const EXIT = {
8
+ /** The command did what it was asked. */
9
+ OK: 0,
10
+ /** The command failed and nothing lasting was produced. */
11
+ FAILED: 1,
12
+ /**
13
+ * The project source was written by this invocation, but no address was
14
+ * reserved: no account on this machine, and no browser to get one. The
15
+ * creator holds a working local project; only registration is deferred.
16
+ */
17
+ DELIVERED_NOT_REGISTERED: 3,
18
+ /** A platform call needed an account and the command did not answer for it. */
19
+ NOT_AUTHENTICATED: 4,
20
+ /** A bounded wait elapsed with nothing handed over. */
21
+ WINDOW_ELAPSED: 64,
22
+ /** The channel ended before anything was handed over. */
23
+ CHANNEL_ENDED: 65,
24
+ };
25
+ // 2 is deliberately unallocated. Shells conventionally use 2 for misuse of a
26
+ // builtin, and a CLI that returns it invites a caller to misread a shell error
27
+ // as ours. The gap is recorded here so a later change does not fill it by
28
+ // looking for the lowest free number.
@@ -10,6 +10,7 @@
10
10
  // be wrong.
11
11
  import path from "node:path";
12
12
  import { SlugTakenError } from "./backend.js";
13
+ import { EXIT } from "./exitCodes.js";
13
14
  import { slugify } from "./slug.js";
14
15
  import { formatSourceRef } from "./sourceRef.js";
15
16
  /** How many times the address prompt re-asks before falling back to the printed block. */
@@ -70,7 +71,9 @@ export async function registerAfterScaffold(deps, opts = {}) {
70
71
  if (!token) {
71
72
  if (!deps.ask) {
72
73
  deps.print("");
73
- deps.print("✗ Not signed in, and signing in needs a browser.");
74
+ deps.print(scaffolded
75
+ ? "→ Not signed in, so no address is reserved yet."
76
+ : "✗ Not signed in, and signing in needs a browser.");
74
77
  deps.print("");
75
78
  if (scaffolded)
76
79
  reassure(deps.print, deps.dirLabel);
@@ -81,9 +84,16 @@ export async function registerAfterScaffold(deps, opts = {}) {
81
84
  deps.print("");
82
85
  deps.print(" Then finish:");
83
86
  resume(deps.print, deps.dirLabel, resumeCommand, needsCd);
87
+ if (scaffolded) {
88
+ deps.print("");
89
+ // B-F2-9(a): the open route must be named in something the creator's
90
+ // agent reads. On a non-TTY this output IS that artifact — the TTY
91
+ // branch's login prompt, which carries the same line, is unreachable here.
92
+ deps.print(" Or don't — the local dev loop needs no account.");
93
+ }
84
94
  deps.print("");
85
95
  deps.print(closing);
86
- return 1;
96
+ return scaffolded ? EXIT.DELIVERED_NOT_REGISTERED : EXIT.FAILED;
87
97
  }
88
98
  deps.print("");
89
99
  deps.print("→ Now registering the project so it gets an address.");
@@ -36,7 +36,11 @@ export interface CreateOptions {
36
36
  export interface CreateResult {
37
37
  /** The full transcript, exactly as the CLI prints it. */
38
38
  message: string;
39
- /** Non-zero when nothing was created (already linked, address taken, no org). */
39
+ /**
40
+ * Non-zero when the address was not reserved. Code 1 means nothing was created
41
+ * (already linked, address taken, no org); code 3 means the project source was
42
+ * written but registration was deferred for want of an account.
43
+ */
40
44
  exitCode: number;
41
45
  }
42
46
  /**
@@ -8,6 +8,7 @@ import { promises as fs } from "node:fs";
8
8
  import path from "node:path";
9
9
  import { BackendError, SlugTakenError, createProject, getProject, } from "./backend.js";
10
10
  import { classifyTarget } from "./classifyTarget.js";
11
+ import { EXIT } from "./exitCodes.js";
11
12
  import { registerAfterScaffold } from "./initFrom.js";
12
13
  import { slugify } from "./slug.js";
13
14
  import { detectPackageManager, installDependencies, scaffoldFromTemplate, } from "../scaffold/index.js";
@@ -169,7 +170,10 @@ export async function createCommand(deps, opts = {}) {
169
170
  name: opts.name ?? path.basename(target),
170
171
  slug: opts.slug ?? slugify(opts.name ?? path.basename(target)),
171
172
  });
172
- if (code !== 0)
173
+ // The gate is DELIVERY, not zero. A run that wrote the source and deferred
174
+ // only the address still delivered a project, so it still prints how to run
175
+ // it. The endings that stay exit 1 delivered nothing and correctly skip this.
176
+ if (code !== 0 && code !== EXIT.DELIVERED_NOT_REGISTERED)
173
177
  return code;
174
178
  if (scaffolded) {
175
179
  // This reader has never run the dev server, so the block that fits is the one
@@ -187,7 +191,10 @@ export async function createCommand(deps, opts = {}) {
187
191
  for (const line of alignedSteps(steps))
188
192
  deps.print(line);
189
193
  }
190
- return 0;
194
+ // Printing the steps must not launder the ending: a delivered-not-registered
195
+ // run still reports 3, so a caller never reads success for an unregistered
196
+ // project.
197
+ return code;
191
198
  }
192
199
  /** Two columns, aligned on the widest command, so the block reads as a table. */
193
200
  function alignedSteps(steps) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincentt-xr/cli",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
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",