shopstack 0.2.0 → 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shopstack
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # shopstack
2
2
 
3
- Dependency-free JavaScript client and CLI for Shopstack's asynchronous checkout API.
3
+ JavaScript client and CLI for Shopstack's asynchronous checkout API.
4
4
 
5
5
  ## Install
6
6
 
@@ -12,22 +12,25 @@ npm install -g shopstack
12
12
 
13
13
  Node.js 18 or newer is required.
14
14
 
15
- Version 0.2.0 defaults to Shopstack's currently deployed public staging API at
16
- `https://shopstack-staging.shopstack.workers.dev/v1`. Set
15
+ The CLI and client default to Shopstack's production API at
16
+ `https://api.shopstack.ai/v1`. Set
17
17
  `SHOPSTACK_API_URL` only when targeting a different Shopstack environment.
18
18
 
19
- ## Personal account
19
+ ## Verified signup
20
20
 
21
21
  ```bash
22
- shopstack signup user --email you@example.com
22
+ shopstack signup
23
23
  ```
24
24
 
25
- This starts a 15-minute signup and waits while you open the verification email.
26
- No account or API key exists until the link is consumed. The CLI then retrieves
27
- the first key with its private polling capability and stores it in
25
+ The command asks for email and Personal or Developer account type. It starts a
26
+ 15-minute signup and waits while you open the verification email. No account or
27
+ API key exists until the link is consumed. The CLI generates and privately
28
+ persists all retry and polling capabilities before the first request, then
29
+ retrieves the first key after verification and stores it in
28
30
  `~/.config/shopstack/config.json` with file mode `0600`; it never prints the
29
- key or polling capability. It checkpoints the pending signup before polling. If
30
- the command is interrupted, resume it with:
31
+ key, recovery capability, or polling capability. If the command is interrupted,
32
+ rerun `shopstack signup`; the matching pending attempt resumes automatically.
33
+ The explicit helper also remains available:
31
34
 
32
35
  ```bash
33
36
  shopstack signup resume sup_...
@@ -36,7 +39,7 @@ shopstack signup resume sup_...
36
39
  ## Developer account and users
37
40
 
38
41
  ```bash
39
- shopstack signup developer --email developer@example.com
42
+ shopstack signup
40
43
  shopstack users create --external-id customer-123 --profile customer-123
41
44
  ```
42
45
 
@@ -65,7 +68,7 @@ phase. It deliberately has no card-input or payment-approval tool.
65
68
 
66
69
  The canonical agent skill ships as `SKILL.md` in this package. After
67
70
  publication it is available at
68
- `https://unpkg.com/shopstack@0.2.0/SKILL.md` with the release-pinned package.
71
+ `https://unpkg.com/shopstack@0.2.2/SKILL.md` with the release-pinned package.
69
72
 
70
73
  ## Connections
71
74
 
@@ -110,6 +113,12 @@ Then run:
110
113
  shopstack checkout run --file checkout.json
111
114
  ```
112
115
 
116
+ The CLI prints the private owner live-view URL as soon as checkout creation
117
+ succeeds. Do not redirect it into shared logs or expose it to a model. The page
118
+ is view-only unless the model explicitly requests human assistance; while that
119
+ request is active, one owner viewer can use **Take control** and **Return
120
+ control**. **Stop** is always available and never approves payment.
121
+
113
122
  When no provider is selected, the checkout runs normally until the payment
114
123
  form, then asks for card details through a no-echo terminal prompt. Card data is
115
124
  sent only to the protected payment-details endpoint. The CLI separately shows
@@ -125,6 +134,14 @@ Card values are never accepted as command-line flags.
125
134
  ```js
126
135
  import { ShopstackClient } from "shopstack";
127
136
 
137
+ const onboarding = new ShopstackClient();
138
+ const account = await onboarding.signup({
139
+ accountType: "developer",
140
+ email: "developer@example.com",
141
+ onProgress: ({ state }) => console.log(state),
142
+ persistence: secureSignupPersistence,
143
+ });
144
+
128
145
  const shopstack = new ShopstackClient({
129
146
  apiKey: process.env.SHOPSTACK_API_KEY,
130
147
  });
@@ -136,9 +153,18 @@ const result = await shopstack.runCheckout(checkoutRequest, {
136
153
  });
137
154
  ```
138
155
 
156
+ `signup` generates retry state internally and returns the completed account
157
+ identity only after the one-time credential is stored. It never returns the API
158
+ key, recovery key, or polling token. Pass a secure persistence adapter for
159
+ restart recovery and durable credential storage; never use browser storage.
160
+
139
161
  `runCheckout` returns at a required input if its corresponding callback is
140
162
  omitted. Final payment approval is never inferred from a message or from
141
- supplying a card.
163
+ supplying a card. While the checkout is active, the CLI and client use a one-time
164
+ checkout-scoped WebSocket capability for change notification and always fetches
165
+ the canonical resource after a signal. It falls back to bounded revision-aware
166
+ HTTP waiting, then to fixed polling when either newer transport is unavailable.
167
+ Neither the API key nor WebSocket capability is placed in the socket URL.
142
168
 
143
169
  Set `SHOPSTACK_API_URL` to target a different Shopstack API and
144
170
  `SHOPSTACK_CONFIG_FILE` to relocate CLI profiles.
package/SKILL.md CHANGED
@@ -41,14 +41,16 @@ Never ask the model to print or relay a Shopstack API key. The CLI and MCP serve
41
41
  Start verified CLI signup:
42
42
 
43
43
  ```bash
44
- shopstack signup user --email user@example.com
45
- shopstack signup developer --email developer@example.com
44
+ shopstack signup
46
45
  ```
47
46
 
48
- The user must open the time-limited verification link. No account or API key exists before verification. The CLI polls the signup, saves the verified key with mode `0600`, and does not print it.
49
- It checkpoints the pending polling capability before waiting. If the process is
50
- interrupted, use `shopstack signup resume SIGNUP_ID`; the capability remains
51
- private in the same local profile store.
47
+ The command prompts for email and Personal or Developer account type. The user
48
+ must open the time-limited verification link. No account or API key exists
49
+ before verification. The CLI generates and privately stores its retry and
50
+ polling capabilities before the request, polls signup, saves the verified key
51
+ with mode `0600`, and prints none of those credentials. Rerunning
52
+ `shopstack signup` automatically resumes the matching pending attempt after an
53
+ interruption; `shopstack signup resume SIGNUP_ID` remains an explicit helper.
52
54
 
53
55
  After developer signup, create an end user:
54
56
 
@@ -107,12 +109,27 @@ shopstack checkout run --file checkout.json
107
109
  Or create with MCP, then call `poll_checkout`. Display these authoritative fields to the user when they change:
108
110
 
109
111
  - `status`: one of exactly `queued`, `started`, `help_required`, `approval_required`, `submitting`, `complete`, `failed`, `cancelled`;
112
+ - `presentation_revision`: the monotonic revision for user-visible checkout state;
110
113
  - `activity`: bounded present-tense display text;
111
114
  - `intent.name`, `intent.phase`, and `intent.updated_at`: bounded mechanical action progress with no arguments or reasoning;
112
115
  - `required_input`: a typed handoff such as protected payment-card input;
113
116
  - `approval`: the exact amount-bound approval request when present.
114
117
 
115
- Poll every two seconds for `queued`, `started`, and `submitting`; every five seconds for `help_required` and `approval_required`; stop at `complete`, `failed`, or `cancelled`.
118
+ The CLI and JavaScript client subscribe with a one-time checkout-scoped
119
+ WebSocket capability. Each valid notification means the presentation revision
120
+ changed; the client then fetches the canonical checkout before displaying or
121
+ acting on it. The notification is not checkout state truth and never grants
122
+ payment authority. The capability belongs in the WebSocket subprotocol, never
123
+ the URL, logs, model context, or messages. If WebSocket delivery is unavailable,
124
+ the client falls back to bounded HTTP waiting and then fixed polling.
125
+
126
+ MCP and manual integrations poll every two seconds for `queued`, `started`, and
127
+ `submitting`; every five seconds for `help_required` and `approval_required`;
128
+ stop at `complete`, `failed`, or `cancelled`.
129
+
130
+ The optional `live_view_url` is a private owner-viewer capability. Show it only
131
+ to the initiating user. Do not store it in browser storage, analytics, logs,
132
+ model context, or ordinary messages.
116
133
 
117
134
  ## Respond at typed boundaries
118
135
 
package/bin/shopstack CHANGED
@@ -5,6 +5,8 @@ import { runCli } from "../src/cli.js";
5
5
  try {
6
6
  await runCli(process.argv.slice(2));
7
7
  } catch (error) {
8
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
8
+ process.stderr.write(
9
+ `${error instanceof Error ? error.message : String(error)}\n`,
10
+ );
9
11
  process.exitCode = 1;
10
12
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shopstack",
3
- "version": "0.2.0",
4
- "description": "Shopstack API client and command-line checkout tools.",
3
+ "version": "0.2.2",
4
+ "description": "Production Shopstack SDK and CLI for agentic checkout.",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {
@@ -23,17 +23,41 @@
23
23
  "shopstack": "bin/shopstack"
24
24
  },
25
25
  "scripts": {
26
+ "check": "npm run format:check && npm run test:coverage",
27
+ "format:check": "prettier --check .",
26
28
  "shopstack": "node ./bin/shopstack",
27
- "test": "node --test"
29
+ "test": "node --test test",
30
+ "test:coverage": "node --test --experimental-test-coverage test",
31
+ "prepublishOnly": "npm run check"
28
32
  },
29
33
  "engines": {
30
34
  "node": ">=18"
31
35
  },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/jimbo132/shopstack-cli.git"
39
+ },
40
+ "homepage": "https://github.com/jimbo132/shopstack-cli#readme",
41
+ "bugs": {
42
+ "url": "https://github.com/jimbo132/shopstack-cli/issues"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "sideEffects": false,
48
+ "dependencies": {
49
+ "ws": "8.21.3"
50
+ },
32
51
  "license": "MIT",
33
52
  "keywords": [
34
53
  "shopstack",
35
54
  "cli",
36
55
  "checkout",
37
- "payments"
38
- ]
56
+ "payments",
57
+ "agentic-commerce",
58
+ "agents"
59
+ ],
60
+ "devDependencies": {
61
+ "prettier": "3.6.2"
62
+ }
39
63
  }
package/src/cli.js CHANGED
@@ -4,25 +4,50 @@ import { createInterface } from "node:readline/promises";
4
4
  import { ShopstackClient } from "./client.js";
5
5
  import { ConfigStore } from "./config.js";
6
6
 
7
- const HELP = `Shopstack
7
+ const VERSION = "0.2.2";
8
+
9
+ const HELP = `Shopstack CLI ${VERSION}
10
+
11
+ Usage:
12
+ shopstack <command> [options]
8
13
 
9
14
  Account setup:
15
+ shopstack signup
16
+ # Create or resume an email-verified Personal or Developer profile.
10
17
  shopstack signup user --email EMAIL
18
+ # Create a Personal profile without interactive account-type prompts.
11
19
  shopstack signup developer --email EMAIL
20
+ # Create a Developer management profile without interactive prompts.
12
21
  shopstack signup resume SIGNUP_ID
22
+ # Resume a known pending email-verification flow.
13
23
  shopstack users create --external-id ID [--profile NAME]
24
+ # Create an independently scoped user from a Developer profile.
14
25
  shopstack profiles list
26
+ # List local profiles without printing their credentials.
15
27
  shopstack profiles use NAME
28
+ # Select the profile used by later commands.
16
29
 
17
30
  Payment connection:
18
31
  shopstack connect list
32
+ # Inspect payment connections for the active user profile.
19
33
  shopstack connect link
34
+ # Connect Link Agentic Wallet in the trusted browser flow.
20
35
 
21
36
  Checkout:
22
37
  shopstack checkout create --file checkout.json
38
+ # Create a checkout and return control immediately.
23
39
  shopstack checkout run --file checkout.json
40
+ # Create, monitor, and complete a checkout interactively.
24
41
  shopstack checkout get CHECKOUT_ID
42
+ # Read the canonical current checkout state.
25
43
  shopstack checkout cancel CHECKOUT_ID
44
+ # Cancel a checkout that has not reached a terminal state.
45
+
46
+ Options:
47
+ -h, --help
48
+ # Show this command reference.
49
+ -v, --version
50
+ # Print the installed Shopstack CLI version.
26
51
  `;
27
52
 
28
53
  function parseOptions(args, allowed) {
@@ -54,6 +79,11 @@ function required(options, name) {
54
79
  return value;
55
80
  }
56
81
 
82
+ function isAffirmative(value) {
83
+ const answer = String(value).trim().toLowerCase();
84
+ return answer === "y" || answer === "yes";
85
+ }
86
+
57
87
  function writeJson(stream, value) {
58
88
  stream.write(`${JSON.stringify(value, null, 2)}\n`);
59
89
  }
@@ -145,9 +175,72 @@ async function saveVerifiedSignup(result, profileName, configStore) {
145
175
  );
146
176
  }
147
177
 
178
+ function signupPersistence(configStore, profileName) {
179
+ return {
180
+ async loadPending(input) {
181
+ return typeof configStore.findPendingSignup === "function"
182
+ ? configStore.findPendingSignup(input)
183
+ : undefined;
184
+ },
185
+ async savePending(state) {
186
+ await configStore.savePendingSignup({ ...state, profile: profileName });
187
+ },
188
+ async completePending(state, result) {
189
+ const pendingId = state.attemptId ?? state.signupId ?? state.id;
190
+ if (typeof configStore.completePendingSignup === "function") {
191
+ await configStore.completePendingSignup(pendingId, profileName, result);
192
+ return;
193
+ }
194
+ await saveVerifiedSignup(result, profileName, configStore);
195
+ await configStore.deletePendingSignup(pendingId);
196
+ },
197
+ async deletePending(state) {
198
+ await configStore.deletePendingSignup(
199
+ state.attemptId ?? state.signupId ?? state.id,
200
+ );
201
+ },
202
+ };
203
+ }
204
+
205
+ async function reportSignupProgress(progress, stream) {
206
+ switch (progress.state) {
207
+ case "email_sent":
208
+ stream.write("Verification email sent.\n");
209
+ return;
210
+ case "waiting":
211
+ stream.write("Waiting for verification...\n");
212
+ return;
213
+ case "verified":
214
+ stream.write("✓ Email verified\n");
215
+ return;
216
+ case "complete":
217
+ stream.write("✓ Shopstack account created\n");
218
+ stream.write("✓ Credentials saved securely\n");
219
+ return;
220
+ case "expired":
221
+ stream.write("Signup expired. Start again to receive a new email.\n");
222
+ return;
223
+ case "rate_limited":
224
+ stream.write(
225
+ "Signup is rate-limited. Retry after the indicated delay.\n",
226
+ );
227
+ return;
228
+ case "conflict":
229
+ stream.write("Signup retry state conflicted and was cleared.\n");
230
+ return;
231
+ case "retryable_failure":
232
+ stream.write(
233
+ "Signup paused after a retryable failure. Run signup again to resume.\n",
234
+ );
235
+ return;
236
+ default:
237
+ return;
238
+ }
239
+ }
240
+
148
241
  async function activeClient(dependencies, requiredKind = "user") {
149
242
  const profile = await dependencies.configStore.activeProfile();
150
- const environmentKey = process.env.SHOPSTACK_API_KEY;
243
+ const environmentKey = dependencies.env.SHOPSTACK_API_KEY;
151
244
  const apiKey = environmentKey || profile?.apiKey;
152
245
  const keyType = environmentKey ? requiredKind : profile?.keyType;
153
246
  if (!apiKey)
@@ -158,7 +251,7 @@ async function activeClient(dependencies, requiredKind = "user") {
158
251
  return {
159
252
  client: dependencies.clientFactory({
160
253
  apiKey,
161
- baseUrl: process.env.SHOPSTACK_API_URL,
254
+ baseUrl: dependencies.env.SHOPSTACK_API_URL,
162
255
  }),
163
256
  profile,
164
257
  };
@@ -175,13 +268,23 @@ export async function runCli(args, supplied = {}) {
175
268
  stderr: process.stderr,
176
269
  stdin: process.stdin,
177
270
  stdout: process.stdout,
271
+ env: process.env,
178
272
  ...supplied,
179
273
  };
180
274
  const [group, action, ...rest] = args;
181
- if (group === undefined || group === "help" || group === "--help") {
275
+ if (
276
+ group === undefined ||
277
+ group === "help" ||
278
+ group === "--help" ||
279
+ group === "-h"
280
+ ) {
182
281
  dependencies.stdout.write(HELP);
183
282
  return;
184
283
  }
284
+ if (group === "--version" || group === "-v") {
285
+ dependencies.stdout.write(`${VERSION}\n`);
286
+ return;
287
+ }
185
288
 
186
289
  if (group === "signup") {
187
290
  if (action === "resume") {
@@ -190,65 +293,130 @@ export async function runCli(args, supplied = {}) {
190
293
  }
191
294
  const pending = await dependencies.configStore.pendingSignup(rest[0]);
192
295
  if (pending === undefined) {
193
- throw new Error("That signup is not present in the local profile store.");
296
+ throw new Error(
297
+ "That signup is not present in the local profile store.",
298
+ );
194
299
  }
195
300
  const client = dependencies.clientFactory({
196
- baseUrl: process.env.SHOPSTACK_API_URL,
301
+ baseUrl: dependencies.env.SHOPSTACK_API_URL,
302
+ });
303
+ const result = await client.signup({
304
+ accountType: pending.accountType,
305
+ email: pending.email,
306
+ onProgress: (progress) =>
307
+ reportSignupProgress(progress, dependencies.stderr),
308
+ persistence: signupPersistence(
309
+ dependencies.configStore,
310
+ pending.profile,
311
+ ),
197
312
  });
198
- const result = await client.waitForAccountSignup(
199
- pending.id,
200
- pending.pollToken,
201
- );
202
- await saveVerifiedSignup(result, pending.profile, dependencies.configStore);
203
- await dependencies.configStore.deletePendingSignup(pending.id);
204
313
  writeJson(dependencies.stdout, {
205
314
  ...sanitizedAccountResult(result),
206
315
  profile: pending.profile,
207
316
  });
208
317
  return;
209
318
  }
210
- if (action !== "user" && action !== "developer") {
319
+ if (action !== undefined && action !== "user" && action !== "developer") {
211
320
  throw new Error(
212
321
  "Use `shopstack signup user` or `shopstack signup developer`.",
213
322
  );
214
323
  }
324
+ const signupArgs = action === undefined ? [] : rest;
215
325
  const { options, positional } = parseOptions(
216
- rest,
326
+ signupArgs,
217
327
  new Set(["email", "profile"]),
218
328
  );
219
329
  if (positional.length > 0) throw new Error("Unexpected signup argument.");
220
- const email = required(options, "email");
330
+ const pendingCandidates =
331
+ action === undefined &&
332
+ typeof dependencies.configStore.pendingSignups === "function"
333
+ ? await dependencies.configStore.pendingSignups()
334
+ : [];
335
+ const resumable =
336
+ pendingCandidates.length === 1 ? pendingCandidates[0] : undefined;
337
+ let accountType;
338
+ let email;
339
+ if (resumable !== undefined) {
340
+ accountType = resumable.accountType;
341
+ email = resumable.email;
342
+ dependencies.stderr.write("Resuming pending signup.\n");
343
+ } else if (action === undefined) {
344
+ email = String(await visiblePrompt("Email: ", dependencies)).trim();
345
+ if (email.length === 0) throw new Error("Email is required.");
346
+ const selected = String(
347
+ await visiblePrompt(
348
+ "Account type (Personal / Developer): ",
349
+ dependencies,
350
+ ),
351
+ )
352
+ .trim()
353
+ .toLowerCase();
354
+ if (selected === "personal" || selected === "user") {
355
+ accountType = "personal";
356
+ } else if (selected === "developer") {
357
+ accountType = "developer";
358
+ } else {
359
+ throw new Error("Account type must be Personal or Developer.");
360
+ }
361
+ } else {
362
+ accountType = action === "user" ? "personal" : "developer";
363
+ email = required(options, "email");
364
+ }
221
365
  const client = dependencies.clientFactory({
222
- baseUrl: process.env.SHOPSTACK_API_URL,
366
+ baseUrl: dependencies.env.SHOPSTACK_API_URL,
223
367
  });
224
- const accountType = action === "user" ? "personal" : "developer";
225
368
  const profileName =
226
- options.profile ?? (action === "developer" ? "developer" : "default");
227
- const signup = await client.startAccountSignup({
369
+ options.profile ??
370
+ resumable?.profile ??
371
+ (accountType === "developer" ? "developer" : "default");
372
+ const result = await client.signup({
228
373
  accountType,
229
374
  email,
375
+ onProgress: (progress) =>
376
+ reportSignupProgress(progress, dependencies.stderr),
377
+ persistence: signupPersistence(dependencies.configStore, profileName),
230
378
  });
231
- await dependencies.configStore.savePendingSignup({
232
- accountType: signup.account_type,
233
- email: signup.email,
234
- expiresAt: signup.expires_at,
235
- id: signup.id,
236
- pollToken: signup.poll_token,
237
- profile: profileName,
238
- });
239
- dependencies.stderr.write(
240
- `Verification email sent to ${signup.email}. Open the link before ${signup.expires_at}. If interrupted, resume signup ${signup.id}.\n`,
241
- );
242
- const result = await client.waitForAccountSignup(
243
- signup.id,
244
- signup.poll_token,
245
- );
246
- await saveVerifiedSignup(result, profileName, dependencies.configStore);
247
- await dependencies.configStore.deletePendingSignup(signup.id);
248
379
  writeJson(dependencies.stdout, {
249
380
  ...sanitizedAccountResult(result),
250
381
  profile: profileName,
251
382
  });
383
+ if (accountType === "developer") {
384
+ dependencies.stderr.write(
385
+ "The developer management credential cannot run user checkouts. Create a user profile with `shopstack users create --external-id ID`.\n",
386
+ );
387
+ if (
388
+ action === undefined &&
389
+ isAffirmative(
390
+ await visiblePrompt(
391
+ "Create the first developer-owned user now? (y/N): ",
392
+ dependencies,
393
+ ),
394
+ )
395
+ ) {
396
+ const externalId = String(
397
+ await visiblePrompt("User external ID: ", dependencies),
398
+ ).trim();
399
+ if (externalId.length === 0) {
400
+ throw new Error("User external ID is required.");
401
+ }
402
+ const { client: developerClient, profile } = await activeClient(
403
+ dependencies,
404
+ "developer",
405
+ );
406
+ const user = await developerClient.createUser({ externalId });
407
+ await dependencies.configStore.saveProfile(
408
+ externalId,
409
+ {
410
+ accountId: profile.accountId,
411
+ apiKey: user.api_key,
412
+ keyType: "user",
413
+ userId: user.id,
414
+ },
415
+ { activate: true },
416
+ );
417
+ writeJson(dependencies.stdout, sanitizedUserResult(user, externalId));
418
+ }
419
+ }
252
420
  return;
253
421
  }
254
422
 
@@ -324,6 +492,11 @@ export async function runCli(args, supplied = {}) {
324
492
  const { client } = await activeClient(dependencies, "user");
325
493
  const request = await dependencies.readJsonFile(required(options, "file"));
326
494
  const result = await client.runCheckout(request, {
495
+ onCreated: (checkout) => {
496
+ if (typeof checkout.live_view_url === "string") {
497
+ dependencies.stderr.write(`Live view: ${checkout.live_view_url}\n`);
498
+ }
499
+ },
327
500
  onProgress: (checkout) => {
328
501
  const intent =
329
502
  checkout.intent?.name === undefined
@@ -383,4 +556,4 @@ export async function runCli(args, supplied = {}) {
383
556
  throw new Error("Unknown command. Run `shopstack help`.");
384
557
  }
385
558
 
386
- export { HELP };
559
+ export { HELP, VERSION };