@bitmagic/cli 0.1.46-dev.2 → 0.1.46-dev.4

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.
Files changed (81) hide show
  1. package/README.md +46 -0
  2. package/dist/auth/session.js +1 -1
  3. package/dist/auth/session.js.map +1 -1
  4. package/dist/auth/subscribe-flow.d.ts +30 -6
  5. package/dist/auth/subscribe-flow.js +64 -29
  6. package/dist/auth/subscribe-flow.js.map +1 -1
  7. package/dist/bin.js +6 -2
  8. package/dist/bin.js.map +1 -1
  9. package/dist/cli.d.ts +43 -2
  10. package/dist/cli.js +78 -7
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/dev.js +9 -0
  13. package/dist/commands/dev.js.map +1 -1
  14. package/dist/commands/forge.js +1 -1
  15. package/dist/commands/forge.js.map +1 -1
  16. package/dist/commands/generate.js +9 -1
  17. package/dist/commands/generate.js.map +1 -1
  18. package/dist/commands/init.js +6 -0
  19. package/dist/commands/init.js.map +1 -1
  20. package/dist/commands/login.js +15 -11
  21. package/dist/commands/login.js.map +1 -1
  22. package/dist/commands/reset-account.d.ts +103 -0
  23. package/dist/commands/reset-account.js +227 -0
  24. package/dist/commands/reset-account.js.map +1 -0
  25. package/dist/commands/subscribe.d.ts +13 -1
  26. package/dist/commands/subscribe.js +21 -17
  27. package/dist/commands/subscribe.js.map +1 -1
  28. package/dist/commands/upgrade.d.ts +2 -1
  29. package/dist/commands/upgrade.js +12 -5
  30. package/dist/commands/upgrade.js.map +1 -1
  31. package/dist/config/environments.d.ts +14 -0
  32. package/dist/config/environments.js +22 -0
  33. package/dist/config/environments.js.map +1 -1
  34. package/dist/errors.d.ts +10 -1
  35. package/dist/errors.js +11 -1
  36. package/dist/errors.js.map +1 -1
  37. package/dist/forge/run-pipeline.js +1 -1
  38. package/dist/forge/run-pipeline.js.map +1 -1
  39. package/dist/forge/stream.js +10 -5
  40. package/dist/forge/stream.js.map +1 -1
  41. package/dist/forge/upload-proxy.js +2 -0
  42. package/dist/forge/upload-proxy.js.map +1 -1
  43. package/dist/generate/stream.js +10 -5
  44. package/dist/generate/stream.js.map +1 -1
  45. package/dist/http/client.d.ts +6 -2
  46. package/dist/http/client.js +22 -12
  47. package/dist/http/client.js.map +1 -1
  48. package/dist/http/spark-refusal.d.ts +11 -0
  49. package/dist/http/spark-refusal.js +13 -0
  50. package/dist/http/spark-refusal.js.map +1 -1
  51. package/dist/publish/client.js +3 -1
  52. package/dist/publish/client.js.map +1 -1
  53. package/dist/scaffold/agents-md.d.ts +2 -1
  54. package/dist/scaffold/agents-md.js +7 -2
  55. package/dist/scaffold/agents-md.js.map +1 -1
  56. package/dist/scaffold/engine-download.js +5 -18
  57. package/dist/scaffold/engine-download.js.map +1 -1
  58. package/dist/scaffold/project-files.d.ts +3 -2
  59. package/dist/scaffold/project-files.js +46 -2
  60. package/dist/scaffold/project-files.js.map +1 -1
  61. package/dist/scaffold/project.d.ts +30 -0
  62. package/dist/scaffold/project.js +55 -29
  63. package/dist/scaffold/project.js.map +1 -1
  64. package/dist/scaffold/upgrade-project.js +19 -33
  65. package/dist/scaffold/upgrade-project.js.map +1 -1
  66. package/dist/telemetry/command-context.d.ts +73 -0
  67. package/dist/telemetry/command-context.js +114 -0
  68. package/dist/telemetry/command-context.js.map +1 -0
  69. package/dist/telemetry/report.d.ts +43 -0
  70. package/dist/telemetry/report.js +123 -0
  71. package/dist/telemetry/report.js.map +1 -0
  72. package/dist/telemetry/request-headers.d.ts +14 -0
  73. package/dist/telemetry/request-headers.js +48 -0
  74. package/dist/telemetry/request-headers.js.map +1 -0
  75. package/dist/update/check.d.ts +14 -0
  76. package/dist/update/check.js +17 -1
  77. package/dist/update/check.js.map +1 -1
  78. package/dist/update/notice.d.ts +40 -0
  79. package/dist/update/notice.js +53 -0
  80. package/dist/update/notice.js.map +1 -1
  81. package/package.json +4 -4
package/README.md CHANGED
@@ -92,6 +92,7 @@ browser reloads itself on every change and the assets panel shows each generatio
92
92
  | `bitmagic usage [--days N]` | Where this account's sparks went, and what Pro allowance is left. |
93
93
  | `bitmagic allowance [--allow-sparks \| --block-sparks]` | The two Pro allowance windows, and whether your purchased sparks may fund work once they run out. `--allow-sparks` needs a real terminal — it authorises spending your money, so an agent cannot run it for you. |
94
94
  | `bitmagic logout [--env <env>]` | Remove stored credentials for an environment. |
95
+ | `bitmagic reset-account [--env <env>] [--yes] [--keep-cli]` | **Deletes your account** on `dev` or `local` so the first-run experience can be tested again — games, sparks, profile, terms acceptance and Bitmagic Pro (cancelled in Stripe first). Then clears that environment's stored credentials **and uninstalls this CLI**, so the next run starts where a new creator starts: `npm install -g @bitmagic/cli`. `--keep-cli` skips that last step. Refuses `prod`, where the endpoint is not deployed at all. Asks you to type the environment name; `--yes` skips that and is required in a shell with no terminal. Your project directory is left alone — its `gameId` no longer exists, so start the fresh run in a new one. |
95
96
  | `bitmagic whoami [--env <env>]` | Show the identity the CLI is authenticated as, and which environment answered — including where that environment was chosen from. |
96
97
  | `bitmagic init [dir] [--template <id>] [--name <name>] [--idea "<pitch>"] [--env <env>] [--force]` | Scaffold a new project: mints a game, downloads the vendored engine, writes `AGENTS.md`, `GAME-DESIGN.md` and templates. Starts from `empty-3d` unless told otherwise. `--idea` seeds the design doc's pitch **and** picks the template whose camera and controls fit it — "a doom-like corridor shooter" scaffolds `first-person`, "jump between floating islands" scaffolds `sidescroller`. `--template` overrides both; a suggestion that fails for any reason falls back to `empty-3d` rather than failing the scaffold. |
97
98
  | `bitmagic check` | Typecheck (`tsc --noEmit`) against the vendored engine. Fast; does not prove the game runs. |
@@ -174,6 +175,14 @@ the release; `@bitmagic/cli@dev` is the prerelease line, developed against `dev`
174
175
  endpoints it depends on exist first. Running a dev build against an environment that has not caught
175
176
  up fails on endpoints that are not there yet — so pair `@dev` with `bitmagic login --env dev`.
176
177
 
178
+ **Inside a project, the pin decides the line**, and nobody should be asked which one they want:
179
+ `dev` and `local` projects take `@bitmagic/cli@dev`, `prod` projects take the plain
180
+ `@bitmagic/cli`. Run a command in a project on the other line and the CLI opens with a notice
181
+ naming the install to switch — and prints only that one, in place of the usual "a newer CLI is
182
+ available" nudge, so there is never a choice of two install commands. The AGENTS.md the CLI
183
+ scaffolds carries the same rule with the project's own command already filled in, which is what
184
+ keeps an agent from putting the question to you.
185
+
177
186
  ## Project layout and artifacts
178
187
 
179
188
  ```
@@ -561,6 +570,43 @@ Three nudges, all advisory — nothing is ever blocked because something is out
561
570
  suggest `bitmagic upgrade`. Publishing is never refused for an old engine — the prompt belongs
562
571
  where rebuilding is cheap, not at the moment you ship.
563
572
 
573
+ ## Usage reporting
574
+
575
+ While you are logged in, each command tells Bitmagic how it went when it ends. That is: the command
576
+ name, whether it succeeded, its exit code and a failure *category* (`unreachable`, `pro_expired`,
577
+ `insufficient_sparks`, …), how long it took, and the CLI, Node and OS versions. Commands that talk to
578
+ Bitmagic anyway — `generate`, `forge`, `publish` — carry the same identification on the calls they
579
+ already make, which is how a spark charge can be attributed to the command that caused it.
580
+
581
+ **What is never sent:** your game's source, file names, paths, or command output. Failures are
582
+ reported as categories, never as messages, because a message can quote a path.
583
+
584
+ **What you type into a command is kept.** The text you pass to `bitmagic forge`, `bitmagic
585
+ generate`, `bitmagic cover` and `bitmagic init --idea` — the descriptions of the world, the asset,
586
+ the game you want — is stored against your account so we can see what creators are trying to make
587
+ and where the generators fall short. It is the same thing the web editor already keeps for prompts
588
+ typed there, and it goes to the same place. None of it reaches Google Analytics, which only ever
589
+ receives counts, outcomes and timings.
590
+
591
+ If your agent passes it, the wording *you* used when you asked it is kept alongside the command's
592
+ own text. That is optional and most agents will not send it.
593
+
594
+ This does not include what you type into Claude Code, Codex or any other agent. Bitmagic never sees
595
+ that — the CLI only ever receives the arguments your agent chooses to pass it.
596
+
597
+ Set `DO_NOT_TRACK=1` in your environment to switch the end-of-command report off. Nothing is
598
+ collected for it in that case — not even the file reads it would have needed.
599
+
600
+ It does **not** switch off the paragraph above. The text you pass to `forge`, `generate`, `cover`
601
+ and `init --idea` is not telemetry: it is the request, and the server cannot generate anything
602
+ without it. If you would rather it were not kept, the honest answer is that today there is no flag
603
+ for that — tell us and we will add one.
604
+
605
+ The report is deliberately unobtrusive but it is not free: it is capped at 1.5 seconds per request
606
+ (two at worst, when your access token is due for a refresh first), it never prints, and it can never
607
+ fail a command — but it does happen at exit, so a command can take that much longer to return on a
608
+ network that is dropping packets. It is skipped entirely when you are logged out.
609
+
564
610
  ## Licensing
565
611
 
566
612
  `bitmagic init` vendors the engine into your project as readable source. It is Bitmagic's IP,
@@ -6,7 +6,7 @@ const EXPIRY_SKEW_MS = 60_000;
6
6
  export async function getAccessToken(environment, clientId, deps, baseDir = defaultBaseDir()) {
7
7
  const stored = readCredentials(environment.name, baseDir);
8
8
  if (!stored) {
9
- throw new CliError(`You are not logged in to the "${environment.name}" environment. Run \`bitmagic login\`.`, 2);
9
+ throw new CliError(`You are not logged in to the "${environment.name}" environment. Run \`bitmagic login\`.`, 2, 'not_logged_in');
10
10
  }
11
11
  const now = deps.now ?? Date.now;
12
12
  if (stored.expiresAt - EXPIRY_SKEW_MS > now()) {
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAuB,MAAM,kBAAkB,CAAC;AAE3E,oEAAoE;AACpE,MAAM,cAAc,GAAG,MAAM,CAAC;AAE9B,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,WAAwB,EACxB,QAAgB,EAChB,IAAoB,EACpB,UAAkB,cAAc,EAAE;IAElC,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,QAAQ,CAChB,iCAAiC,WAAW,CAAC,IAAI,wCAAwC,EACzF,CAAC,CACF,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACjC,IAAI,MAAM,CAAC,SAAS,GAAG,cAAc,GAAG,GAAG,EAAE,EAAE,CAAC;QAC9C,OAAO,MAAM,CAAC,WAAW,CAAC;IAC5B,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAC7F,gBAAgB,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACvD,OAAO,SAAS,CAAC,WAAW,CAAC;AAC/B,CAAC"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAuB,MAAM,kBAAkB,CAAC;AAE3E,oEAAoE;AACpE,MAAM,cAAc,GAAG,MAAM,CAAC;AAE9B,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,WAAwB,EACxB,QAAgB,EAChB,IAAoB,EACpB,UAAkB,cAAc,EAAE;IAElC,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,QAAQ,CAChB,iCAAiC,WAAW,CAAC,IAAI,wCAAwC,EACzF,CAAC,EACD,eAAe,CAChB,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACjC,IAAI,MAAM,CAAC,SAAS,GAAG,cAAc,GAAG,GAAG,EAAE,EAAE,CAAC;QAC9C,OAAO,MAAM,CAAC,WAAW,CAAC;IAC5B,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAC7F,gBAAgB,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACvD,OAAO,SAAS,CAAC,WAAW,CAAC;AAC/B,CAAC"}
@@ -13,6 +13,15 @@ export interface WhoamiResponse {
13
13
  proUntil: string | null;
14
14
  /** Set when the subscription is live but will not renew. Optional: older api-servers omit it. */
15
15
  cancelAtPeriodEnd?: boolean;
16
+ /**
17
+ * The Bitmagic Pro storefront — where Pro is bought OR a Pro voucher redeemed.
18
+ *
19
+ * Optional for the same reason `cancelAtPeriodEnd` is: a CLI published today
20
+ * can be pointed at an api-server deployed before the storefront existed, and
21
+ * must still be able to sell a subscription. Absent means "fall back to
22
+ * minting Stripe Checkout myself".
23
+ */
24
+ subscribeUrl?: string;
16
25
  }
17
26
  /**
18
27
  * PURE. One line describing where the caller's subscription stands.
@@ -42,18 +51,33 @@ export interface SubscribeOptions {
42
51
  noWait?: boolean;
43
52
  }
44
53
  export interface SubscribeResult {
45
- /** True when the subscription was confirmed active before we returned. */
54
+ /** True when Pro was confirmed active before we returned. */
46
55
  pro: boolean;
47
- /** The checkout URL, when one was created (absent if already subscribed). */
48
- checkoutUrl?: string;
56
+ /**
57
+ * Where the creator finishes subscribing: the storefront, or — against an
58
+ * api-server predating it — a Stripe Checkout URL. Always set: every exit from
59
+ * the flow has already opened or printed one.
60
+ */
61
+ subscribeUrl: string;
49
62
  /** Why we stopped waiting, when we did not confirm. */
50
63
  reason?: 'timeout' | 'not-waited';
51
64
  }
52
65
  /**
53
- * Explain that Pro is required, open checkout, and wait for it to land.
66
+ * PURE. The storefront URL to open for this caller.
67
+ *
68
+ * `cli=1` only changes the page's wording — it says "go back to your terminal"
69
+ * once Pro is active. `u` is the account this CLI is authenticated as, so the
70
+ * page can refuse to sell Pro to a DIFFERENT account that happens to be signed
71
+ * in to the browser. That mismatch was impossible while the CLI minted the
72
+ * Stripe session from its own token, and it is invisible from here: the creator
73
+ * would subscribe the wrong account and this poll would run to its timeout.
74
+ */
75
+ export declare function storefrontUrlFor(subscribeUrl: string, userId: string): string;
76
+ /**
77
+ * Explain that Pro is required, open the storefront, and wait for it to land.
54
78
  *
55
79
  * Returns rather than throwing when the creator does not finish: abandoning
56
- * checkout is a decision, not an error, and the credentials from a successful
80
+ * the flow is a decision, not an error, and the credentials from a successful
57
81
  * login are still worth keeping.
58
82
  */
59
- export declare function runSubscribeFlow(environment: Environment, token: string, output: Output, options?: SubscribeOptions, deps?: SubscribeDeps): Promise<SubscribeResult>;
83
+ export declare function runSubscribeFlow(environment: Environment, token: string, me: WhoamiResponse, output: Output, options?: SubscribeOptions, deps?: SubscribeDeps): Promise<SubscribeResult>;
@@ -1,19 +1,33 @@
1
1
  /**
2
2
  * Getting a logged-in creator from "no subscription" to "ready to work".
3
3
  *
4
- * The Bitmagic CLI requires an active Bitmagic Pro subscription, so for a new
5
- * creator the very first command would otherwise be a 403. Rather than print an
6
- * error and a URL to retype, the CLI creates the Stripe Checkout session itself
7
- * and opens it: `bitmagic login` flows straight from the device-code approval
8
- * into paying, in the same browser, and then confirms.
4
+ * The Bitmagic CLI requires active Bitmagic Pro, so for a new creator the very
5
+ * first command would otherwise be a 403. Rather than print an error and a URL
6
+ * to retype, the CLI opens the Bitmagic Pro storefront: `bitmagic login` flows
7
+ * straight from the device-code approval into subscribing, in the same browser,
8
+ * and then confirms.
9
9
  *
10
- * Two api-server routes make this possible, and both live OUTSIDE the CLI's
11
- * entitlement gate for exactly this reason (see cli-onboarding-routes.ts):
12
- * `GET /whoami` answers whether the caller is entitled, and
13
- * `POST /pro/checkout` mints a checkout URL for the caller's own account.
10
+ * ── Why a storefront and not Stripe Checkout ─────────────────────────────────
14
11
  *
15
- * Shared by `login` and by `subscribe`, so a creator who abandoned checkout
16
- * gets an identical second run rather than a different-looking recovery path.
12
+ * This used to POST /pro/checkout and open the Stripe URL directly. That made a
13
+ * comped-Pro voucher unreachable from the CLI even though `pro_days` satisfies
14
+ * the entitlement gate exactly as a subscription does — someone holding a code
15
+ * was shown a card form and nothing else. The storefront offers both, and the
16
+ * poll below does not care which one the creator picked: `whoami` reports a
17
+ * grant and a subscription identically.
18
+ *
19
+ * The URL comes from `whoami` rather than from the CLI's own config, because
20
+ * PORTAL_URL is the api-server's to know. Deriving it from `apiUrl` would be
21
+ * wrong locally, where the api-server is on 3002 and the portal on 4000.
22
+ *
23
+ * Both routes live OUTSIDE the CLI's entitlement gate for the obvious reason
24
+ * (see cli-onboarding-routes.ts): `GET /whoami` answers whether the caller is
25
+ * entitled and where to fix it, and `POST /pro/checkout` — now called by the
26
+ * storefront, and by this file only against an api-server too old to have one —
27
+ * mints a checkout URL for the caller's own account.
28
+ *
29
+ * Shared by `login` and by `subscribe`, so a creator who abandoned the flow gets
30
+ * an identical second run rather than a different-looking recovery path.
17
31
  */
18
32
  import { apiGet, apiPost } from '../http/client.js';
19
33
  import { openInBrowser } from '../open-browser.js';
@@ -50,18 +64,34 @@ export function fetchWhoami(environment, token, deps) {
50
64
  return apiGet(environment, '/api/cli/v1/whoami', token, { fetch: deps.fetch });
51
65
  }
52
66
  /**
53
- * Explain that Pro is required, open checkout, and wait for it to land.
67
+ * PURE. The storefront URL to open for this caller.
68
+ *
69
+ * `cli=1` only changes the page's wording — it says "go back to your terminal"
70
+ * once Pro is active. `u` is the account this CLI is authenticated as, so the
71
+ * page can refuse to sell Pro to a DIFFERENT account that happens to be signed
72
+ * in to the browser. That mismatch was impossible while the CLI minted the
73
+ * Stripe session from its own token, and it is invisible from here: the creator
74
+ * would subscribe the wrong account and this poll would run to its timeout.
75
+ */
76
+ export function storefrontUrlFor(subscribeUrl, userId) {
77
+ const separator = subscribeUrl.includes('?') ? '&' : '?';
78
+ return `${subscribeUrl}${separator}cli=1&u=${encodeURIComponent(userId)}`;
79
+ }
80
+ /**
81
+ * Explain that Pro is required, open the storefront, and wait for it to land.
54
82
  *
55
83
  * Returns rather than throwing when the creator does not finish: abandoning
56
- * checkout is a decision, not an error, and the credentials from a successful
84
+ * the flow is a decision, not an error, and the credentials from a successful
57
85
  * login are still worth keeping.
58
86
  */
59
- export async function runSubscribeFlow(environment, token, output, options = {}, deps = defaultSubscribeDeps) {
60
- const checkout = await apiPost(environment, '/api/cli/v1/pro/checkout', token, {}, {
61
- fetch: deps.fetch,
62
- });
87
+ export async function runSubscribeFlow(environment, token, me, output, options = {}, deps = defaultSubscribeDeps) {
88
+ // An api-server too old to serve a storefront still has to be able to sell a
89
+ // subscription, so fall back to minting Checkout the way this flow used to.
90
+ const url = me.subscribeUrl
91
+ ? storefrontUrlFor(me.subscribeUrl, me.userId)
92
+ : (await apiPost(environment, '/api/cli/v1/pro/checkout', token, {}, { fetch: deps.fetch })).url;
63
93
  output.info('');
64
- output.info('The Bitmagic CLI needs a Bitmagic Pro subscription.');
94
+ output.info('The Bitmagic CLI needs Bitmagic Pro.');
65
95
  output.info('Pro gives you a weekly and a 5-hour spark allowance that refill on their own,');
66
96
  output.info('and pays for generating assets, cover art and worlds.');
67
97
  output.info('');
@@ -69,34 +99,39 @@ export async function runSubscribeFlow(environment, token, output, options = {},
69
99
  // no browser, in a container, and in a log an agent reads back later.
70
100
  const opened = options.noOpen === true
71
101
  ? false
72
- : deps.openInBrowser(checkout.url, { log: (m) => output.info(m) });
73
- output.info(opened ? `Opening checkout in your browser:\n ${checkout.url}` : `Subscribe at:\n ${checkout.url}`);
102
+ : deps.openInBrowser(url, { log: (m) => output.info(m) });
103
+ // Naming the voucher here and not only on the page matters: an agent driving
104
+ // the CLI reads this text, and the human it is working for may be holding a code.
105
+ output.info(opened
106
+ ? `Opening Bitmagic Pro in your browser — subscribe, or redeem a Pro voucher there:\n ${url}`
107
+ : `Subscribe, or redeem a Pro voucher, at:\n ${url}`);
74
108
  if (options.noWait === true) {
75
- return { pro: false, checkoutUrl: checkout.url, reason: 'not-waited' };
109
+ return { pro: false, subscribeUrl: url, reason: 'not-waited' };
76
110
  }
77
111
  output.info('');
78
- output.info('Waiting for your subscription… (Ctrl-C is safe — run `bitmagic subscribe` to resume)');
112
+ output.info('Waiting for Bitmagic Pro… (Ctrl-C is safe — run `bitmagic subscribe` to resume)');
79
113
  const deadline = deps.now() + SUBSCRIBE_POLL_TIMEOUT_MS;
80
114
  while (deps.now() < deadline) {
81
115
  await deps.sleep(SUBSCRIBE_POLL_INTERVAL_MS);
82
116
  // A transient failure mid-poll must not end the flow — the creator may
83
117
  // still be typing their card in. Only a definitive "yes" stops the loop.
84
- let me = null;
118
+ // This answers for a redeemed voucher too: `pro` is entitlement, not billing.
119
+ let current = null;
85
120
  try {
86
- me = await fetchWhoami(environment, token, deps);
121
+ current = await fetchWhoami(environment, token, deps);
87
122
  }
88
123
  catch {
89
124
  continue;
90
125
  }
91
- if (me.pro) {
126
+ if (current.pro) {
92
127
  output.info('');
93
128
  output.info('Bitmagic Pro is active. You are ready — try `bitmagic init`.');
94
- return { pro: true, checkoutUrl: checkout.url };
129
+ return { pro: true, subscribeUrl: url };
95
130
  }
96
131
  }
97
132
  output.info('');
98
- output.info('Still waiting on Stripe. Run `bitmagic usage` once it completes, or');
99
- output.info('`bitmagic subscribe` to start again.');
100
- return { pro: false, checkoutUrl: checkout.url, reason: 'timeout' };
133
+ output.info('Still waiting. If you paid, run `bitmagic usage` once Stripe confirms; otherwise');
134
+ output.info('run `bitmagic subscribe` to start again.');
135
+ return { pro: false, subscribeUrl: url, reason: 'timeout' };
101
136
  }
102
137
  //# sourceMappingURL=subscribe-flow.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"subscribe-flow.js","sourceRoot":"","sources":["../../src/auth/subscribe-flow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subscribe-flow.js","sourceRoot":"","sources":["../../src/auth/subscribe-flow.ts"],"names":[],"mappings":"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"}
package/dist/bin.js CHANGED
@@ -2,7 +2,8 @@
2
2
  import { runMain } from 'citty';
3
3
  import { main } from './cli.js';
4
4
  import { CliError } from './errors.js';
5
- import { pendingUpdateNotice, refreshUpdateCacheInBackground } from './update/check.js';
5
+ import { readPinnedEnvironment } from './config/environments.js';
6
+ import { refreshUpdateCacheInBackground, startupNotice } from './update/check.js';
6
7
  import { currentCliVersion } from './update/cli-version.js';
7
8
  // The version is READ here, not at the import time of anything cli.ts pulls in — cli.test.ts
8
9
  // imports cli.ts for `subCommands`, and a version check triggered against the test runner is
@@ -13,7 +14,10 @@ import { currentCliVersion } from './update/cli-version.js';
13
14
  // costs no network and no measurable time here. A command that exits early (or via process.exit
14
15
  // on a CliError) has still shown it, which printing afterwards could not guarantee.
15
16
  const version = currentCliVersion();
16
- const notice = pendingUpdateNotice(version);
17
+ // The pin is read from the committed bitmagic.json, so running in a project whose environment wants
18
+ // the other npm line says so — and says only that, rather than also offering the newest build of the
19
+ // line you should not be on. See startupNotice.
20
+ const notice = startupNotice(version, readPinnedEnvironment());
17
21
  if (notice !== null)
18
22
  console.error(notice);
19
23
  // Deliberately NOT awaited: this is for the next invocation, not this one. Bounded by its own
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,8BAA8B,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,6FAA6F;AAC7F,6FAA6F;AAC7F,+FAA+F;AAC/F,+BAA+B;AAC/B,EAAE;AACF,kGAAkG;AAClG,gGAAgG;AAChG,oFAAoF;AACpF,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;AACpC,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC5C,IAAI,MAAM,KAAK,IAAI;IAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAE3C,8FAA8F;AAC9F,iGAAiG;AACjG,2FAA2F;AAC3F,KAAK,8BAA8B,CAAC,OAAO,CAAC,CAAC;AAE7C,wFAAwF;AACxF,+FAA+F;AAC/F,8FAA8F;AAC9F,gGAAgG;AAChG,2FAA2F;AAC3F,kGAAkG;AAClG,mGAAmG;AACnG,gGAAgG;AAChG,OAAO,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,EAAE,GAAI,IAAI,CAAC,IAAgC,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC1G,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,8BAA8B,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,6FAA6F;AAC7F,6FAA6F;AAC7F,+FAA+F;AAC/F,+BAA+B;AAC/B,EAAE;AACF,kGAAkG;AAClG,gGAAgG;AAChG,oFAAoF;AACpF,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;AACpC,oGAAoG;AACpG,qGAAqG;AACrG,gDAAgD;AAChD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,EAAE,qBAAqB,EAAE,CAAC,CAAC;AAC/D,IAAI,MAAM,KAAK,IAAI;IAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAE3C,8FAA8F;AAC9F,iGAAiG;AACjG,2FAA2F;AAC3F,KAAK,8BAA8B,CAAC,OAAO,CAAC,CAAC;AAE7C,wFAAwF;AACxF,+FAA+F;AAC/F,8FAA8F;AAC9F,gGAAgG;AAChG,2FAA2F;AAC3F,kGAAkG;AAClG,mGAAmG;AACnG,gGAAgG;AAChG,OAAO,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,EAAE,GAAI,IAAI,CAAC,IAAgC,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC1G,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/cli.d.ts CHANGED
@@ -1,5 +1,28 @@
1
1
  import type { ArgsDef, CommandDef } from 'citty';
2
- export declare function withCleanErrors<T extends ArgsDef>(command: CommandDef<T>): CommandDef<T>;
2
+ import { type BeginCommandInput } from './telemetry/command-context.js';
3
+ import { type CommandReport } from './telemetry/report.js';
4
+ /**
5
+ * What the wrapper needs from the outside world to report a command's outcome. The real ones
6
+ * (below) mark the command as begun and send the beacon to api-server; tests pass stubs so a
7
+ * wrapped command under test never touches `~/.bitmagic` or the network.
8
+ */
9
+ export interface CommandRunDeps {
10
+ begin: (input: BeginCommandInput) => void;
11
+ report: (report: CommandReport) => Promise<void>;
12
+ now: () => number;
13
+ }
14
+ /**
15
+ * Wraps a command's `run` so that (a) a CliError becomes a clean single-line message and exit
16
+ * code, and (b) EVERY run — success, refusal or crash — reports how it went to api-server, once,
17
+ * with the command's name and duration (see telemetry/report.ts). Doing both here, over the
18
+ * whole map, is what makes the reporting complete: there is no per-command call anyone can
19
+ * forget, and the offline commands (`dev`, `build`, `check`, ...) are covered exactly like the
20
+ * ones that talk to the server anyway.
21
+ *
22
+ * `name` is what the report calls the command — `publish`, `generate skybox` — as the creator
23
+ * typed it.
24
+ */
25
+ export declare function withCleanErrors<T extends ArgsDef>(command: CommandDef<T>, name?: string, deps?: CommandRunDeps): CommandDef<T>;
3
26
  /**
4
27
  * Structural check for tests: has this command actually passed through `withCleanErrors`? A leaf
5
28
  * command (one with its own `run`) is wrapped when that `run` is in `wrappedRuns`. A grouping
@@ -28,6 +51,24 @@ declare const rawCommands: {
28
51
  readonly description: "Print the result as JSON on stdout; all progress goes to stderr.";
29
52
  };
30
53
  }>;
54
+ 'reset-account': CommandDef<{
55
+ readonly env: {
56
+ readonly type: "string";
57
+ readonly description: "Environment to reset in (dev, local). Never prod.";
58
+ };
59
+ readonly yes: {
60
+ readonly type: "boolean";
61
+ readonly description: "Skip the confirmation. Required in a non-interactive shell.";
62
+ };
63
+ readonly 'keep-cli': {
64
+ readonly type: "boolean";
65
+ readonly description: string;
66
+ };
67
+ readonly json: {
68
+ readonly type: "boolean";
69
+ readonly description: "Print the result as JSON on stdout; all progress goes to stderr.";
70
+ };
71
+ }>;
31
72
  whoami: CommandDef<{
32
73
  readonly env: {
33
74
  readonly type: "string";
@@ -45,7 +86,7 @@ declare const rawCommands: {
45
86
  };
46
87
  readonly 'no-wait': {
47
88
  readonly type: "boolean";
48
- readonly description: "Open checkout and exit instead of waiting for it to complete.";
89
+ readonly description: "Open the Bitmagic Pro page and exit instead of waiting for it to complete.";
49
90
  };
50
91
  readonly json: {
51
92
  readonly type: "boolean";
package/dist/cli.js CHANGED
@@ -1,8 +1,11 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import { CliError } from './errors.js';
3
3
  import { jsonErrorResult } from './output.js';
4
+ import { beginCommand } from './telemetry/command-context.js';
5
+ import { crashCategory, reportCommandEvent } from './telemetry/report.js';
4
6
  import { loginCommand } from './commands/login.js';
5
7
  import { logoutCommand } from './commands/logout.js';
8
+ import { resetAccountCommand } from './commands/reset-account.js';
6
9
  import { whoamiCommand } from './commands/whoami.js';
7
10
  import { usageCommand } from './commands/usage.js';
8
11
  import { allowanceCommand } from './commands/allowance.js';
@@ -40,13 +43,77 @@ function subCommandsOf(command) {
40
43
  return undefined;
41
44
  return subs;
42
45
  }
43
- export function withCleanErrors(command) {
46
+ const realRunDeps = {
47
+ begin: beginCommand,
48
+ report: reportCommandEvent,
49
+ now: Date.now,
50
+ };
51
+ /**
52
+ * The name the wrapper reports for `command`, when the caller did not give one: its own
53
+ * `meta.name`, or `unknown` for a command that has none. Every entry in `rawCommands` is named
54
+ * from the map key instead (and its subcommands as `parent sub`), so this only decides for a
55
+ * command wrapped on its own — which, in practice, means a test's.
56
+ */
57
+ /**
58
+ * The `--env` this command will actually honour, or undefined.
59
+ *
60
+ * Gated on the command DECLARING an `env` argument, which only eight of the eighteen do — the
61
+ * rest resolve from the project (`resolveEnvironmentForCommand({ cwd })`) and ignore the flag
62
+ * entirely. citty still surfaces an undeclared flag in `args`: `--env=dev` arrives as the string
63
+ * `'dev'` (the space form `--env dev` arrives as `true`, which the type check below would have
64
+ * caught anyway). Reading it unconditionally therefore pointed the usage report at one
65
+ * environment while the command worked against another — `bitmagic publish --env=dev` inside a
66
+ * project pinned to `local` publishes to local and would have reported to dev.
67
+ */
68
+ function declaredExplicitEnv(command, args) {
69
+ const declared = (command.args ?? {});
70
+ if (!Object.prototype.hasOwnProperty.call(declared, 'env'))
71
+ return undefined;
72
+ const value = args?.env;
73
+ return typeof value === 'string' ? value : undefined;
74
+ }
75
+ function commandNameOf(command) {
76
+ // citty's `meta` is a Resolvable (a value, a promise, or a function returning either); every
77
+ // meta in this CLI is a plain object, and a test double that is not simply reports `unknown`.
78
+ const meta = command.meta;
79
+ if (typeof meta !== 'object' || meta === null)
80
+ return 'unknown';
81
+ const name = meta.name;
82
+ return typeof name === 'string' ? name : 'unknown';
83
+ }
84
+ /**
85
+ * Wraps a command's `run` so that (a) a CliError becomes a clean single-line message and exit
86
+ * code, and (b) EVERY run — success, refusal or crash — reports how it went to api-server, once,
87
+ * with the command's name and duration (see telemetry/report.ts). Doing both here, over the
88
+ * whole map, is what makes the reporting complete: there is no per-command call anyone can
89
+ * forget, and the offline commands (`dev`, `build`, `check`, ...) are covered exactly like the
90
+ * ones that talk to the server anyway.
91
+ *
92
+ * `name` is what the report calls the command — `publish`, `generate skybox` — as the creator
93
+ * typed it.
94
+ */
95
+ export function withCleanErrors(command, name = commandNameOf(command), deps = realRunDeps) {
44
96
  const originalRun = command.run;
45
97
  const wrapped = { ...command };
46
98
  if (originalRun) {
47
99
  wrapped.run = async (context) => {
100
+ const json = context.args?.json === true;
101
+ const explicitEnv = declaredExplicitEnv(command, context.args);
102
+ const startedAt = deps.now();
103
+ // Before the run, so every api-server call the command makes is stamped with its name.
104
+ deps.begin({ name, json, explicitEnv, now: deps.now });
105
+ // Awaited, not fired: it is bounded (report.ts), and on the failure path process.exit
106
+ // comes next — a fire-and-forget request would be cut off mid-flight.
107
+ //
108
+ // `Math.max(0, …)` because the clock is `Date.now()` and therefore not monotonic: an NTP
109
+ // step backwards mid-command would otherwise send a negative duration, which api-server
110
+ // rejects — discarding the outcome and the failure category along with it, rather than
111
+ // just the one bad field.
112
+ const finished = (outcome) => deps.report({ stage: 'finished', durationMs: Math.max(0, deps.now() - startedAt), ...outcome });
48
113
  try {
49
- return await originalRun(context);
114
+ const result = await originalRun(context);
115
+ await finished({ ok: true });
116
+ return result;
50
117
  }
51
118
  catch (error) {
52
119
  if (error instanceof CliError) {
@@ -55,13 +122,16 @@ export function withCleanErrors(command) {
55
122
  // document, so an agent parses one stream for the outcome instead of branching between
56
123
  // "parse stdout" on success and "read prose" on failure.
57
124
  console.error(error.message);
58
- if (context.args?.json === true) {
125
+ if (json) {
59
126
  console.log(JSON.stringify(jsonErrorResult(error.message, error.exitCode)));
60
127
  }
128
+ await finished({ ok: false, exitCode: error.exitCode, failure: error.code ?? 'cli_error' });
61
129
  process.exit(error.exitCode);
62
130
  }
63
131
  // Not one of ours: let citty's default handling show it, stack trace included — that's
64
- // a genuine bug, not a user-facing condition we've designed a message for.
132
+ // a genuine bug, not a user-facing condition we've designed a message for. citty exits 1
133
+ // for it, which is what the report says.
134
+ await finished({ ok: false, exitCode: 1, failure: crashCategory(error) });
65
135
  throw error;
66
136
  }
67
137
  };
@@ -72,10 +142,10 @@ export function withCleanErrors(command) {
72
142
  // unrecursed, a CliError thrown from one of those would clear this command's own (nonexistent)
73
143
  // run untouched and hit citty's default handling instead — a raw stack trace, the exact thing
74
144
  // this wrapper exists to prevent. Recurse so every depth gets the same clean single-line
75
- // treatment.
145
+ // treatment — and the same report, named `generate skybox` rather than `skybox`.
76
146
  const subs = subCommandsOf(command);
77
147
  if (subs) {
78
- wrapped.subCommands = Object.fromEntries(Object.entries(subs).map(([name, sub]) => [name, withCleanErrors(sub)]));
148
+ wrapped.subCommands = Object.fromEntries(Object.entries(subs).map(([subName, sub]) => [subName, withCleanErrors(sub, `${name} ${subName}`, deps)]));
79
149
  }
80
150
  return wrapped;
81
151
  }
@@ -101,6 +171,7 @@ export function isWrappedWithCleanErrors(command) {
101
171
  const rawCommands = {
102
172
  login: loginCommand,
103
173
  logout: logoutCommand,
174
+ 'reset-account': resetAccountCommand,
104
175
  whoami: whoamiCommand,
105
176
  subscribe: subscribeCommand,
106
177
  usage: usageCommand,
@@ -117,7 +188,7 @@ const rawCommands = {
117
188
  forge: forgeCommand,
118
189
  publish: publishCommand,
119
190
  };
120
- export const subCommands = Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => [name, withCleanErrors(command)]));
191
+ export const subCommands = Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => [name, withCleanErrors(command, name)]));
121
192
  // This module only builds `main` and exports it (along with `subCommands` and `withCleanErrors`)
122
193
  // for `bin.ts` to run and for cli.test.ts to import — it must not call `runMain` or otherwise
123
194
  // have a side effect when imported, e.g. by cli.test.ts, which needs `subCommands` and
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -29,6 +29,8 @@ import { CORS_ALLOWED_PORT_MAX, CORS_ALLOWED_PORT_MIN, isPortFree, parseLocalPor
29
29
  import { openInBrowser, NO_OPEN_ENV } from '../open-browser.js';
30
30
  import { waitForServer } from '../verify/wait-for-server.js';
31
31
  import { engineUpdateNotice } from '../project/engine-update.js';
32
+ import { reportCommandEvent } from '../telemetry/report.js';
33
+ import { currentCommand } from '../telemetry/command-context.js';
32
34
  /**
33
35
  * Tell the creator, once, if a newer engine exists — the one place where acting on it is cheap.
34
36
  *
@@ -207,6 +209,13 @@ export const devCommand = defineCommand({
207
209
  // the tabs, kept addressable for a second window or a bookmark.
208
210
  void waitForServer(gamePort, 30_000)
209
211
  .then(() => {
212
+ // The one command that reports twice. Every command reports when it ENDS (cli.ts), but
213
+ // a dev server ends by the terminal closing at least as often as by Ctrl-C, and only the
214
+ // latter reaches the wrapper — so the session is counted here, the moment it is actually
215
+ // serving. The duration is the time to get here from the command start: build included,
216
+ // which is most of it. Fire-and-forget: a slow api-server must never delay the banner.
217
+ const commandStartedAt = currentCommand()?.startedAt ?? Date.now();
218
+ void reportCommandEvent({ stage: 'started', ok: true, durationMs: Date.now() - commandStartedAt });
210
219
  // Opened rather than merely printed, because this command is now started as a BACKGROUND
211
220
  // task by the agent that scaffolds the project — so this banner goes to a log the creator
212
221
  // never reads. See open-browser.ts for why `login` makes the opposite call.