@displaydev/cli 0.5.0 → 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.
package/dist/main.js CHANGED
@@ -1,4 +1,12 @@
1
1
  #!/usr/bin/env node
2
+ function _array_like_to_array(arr, len) {
3
+ if (len == null || len > arr.length) len = arr.length;
4
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
5
+ return arr2;
6
+ }
7
+ function _array_without_holes(arr) {
8
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
9
+ }
2
10
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
3
11
  try {
4
12
  var info = gen[key](arg);
@@ -36,6 +44,23 @@ function _instanceof(left, right) {
36
44
  return left instanceof right;
37
45
  }
38
46
  }
47
+ function _iterable_to_array(iter) {
48
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
49
+ }
50
+ function _non_iterable_spread() {
51
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
52
+ }
53
+ function _to_consumable_array(arr) {
54
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
55
+ }
56
+ function _unsupported_iterable_to_array(o, minLen) {
57
+ if (!o) return;
58
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
59
+ var n = Object.prototype.toString.call(o).slice(8, -1);
60
+ if (n === "Object" && o.constructor) n = o.constructor.name;
61
+ if (n === "Map" || n === "Set") return Array.from(n);
62
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
63
+ }
39
64
  function _ts_generator(thisArg, body) {
40
65
  var f, y, t, _ = {
41
66
  label: 0,
@@ -135,91 +160,38 @@ function _ts_generator(thisArg, body) {
135
160
  };
136
161
  }
137
162
  }
138
- import { readFile, mkdir, writeFile, rename, chmod } from 'node:fs/promises';
163
+ import { readFile } from 'node:fs/promises';
139
164
  import { createInterface } from 'node:readline/promises';
140
165
  import { createRequire } from 'node:module';
141
166
  import { execFileSync } from 'node:child_process';
142
- import { homedir, platform } from 'node:os';
143
- import { join, extname } from 'node:path';
167
+ import { platform } from 'node:os';
144
168
  import { Command } from 'commander';
145
- import { ApiClient } from './api-client.js';
169
+ import { ApiClient, ApiError } from './api-client.js';
170
+ import { loadConfig, saveConfig } from './config.js';
146
171
  import { startMcpServer } from './mcp-server.js';
172
+ import { DEFAULT_API_URL, DeviceCodeDeniedError, DeviceCodeExpiredError, DeviceCodeFailedError, InvalidFlagError, PublishArgsError, classifyBrandingError, parseShortIdAndVersion, parseShowBrandingFlag, pollDeviceToken, readApiKeyFromTty, readStreamToString, resolveAuth as resolveAuthFromEnvAndConfig, validatePublishArgs } from './main-helpers.js';
147
173
  var require = createRequire(import.meta.url);
148
174
  var version = require('../package.json').version;
149
- var DEFAULT_API_URL = 'https://api.display.dev';
150
- var CONFIG_DIR = join(homedir(), '.displaydev');
151
- var CONFIG_PATH = join(CONFIG_DIR, 'config.json');
152
- function loadConfig() {
153
- return _async_to_generator(function() {
154
- var raw, unused;
155
- return _ts_generator(this, function(_state) {
156
- switch(_state.label){
157
- case 0:
158
- _state.trys.push([
159
- 0,
160
- 2,
161
- ,
162
- 3
163
- ]);
164
- return [
165
- 4,
166
- readFile(CONFIG_PATH, 'utf-8')
167
- ];
168
- case 1:
169
- raw = _state.sent();
170
- return [
171
- 2,
172
- JSON.parse(raw)
173
- ];
174
- case 2:
175
- unused = _state.sent();
176
- return [
177
- 2,
178
- null
179
- ];
180
- case 3:
181
- return [
182
- 2
183
- ];
184
- }
185
- });
186
- })();
187
- }
188
- function saveConfig(config) {
175
+ function resolveAuthOrConfig() {
189
176
  return _async_to_generator(function() {
190
- var tmpPath;
177
+ var auth;
191
178
  return _ts_generator(this, function(_state) {
192
179
  switch(_state.label){
193
180
  case 0:
194
181
  return [
195
182
  4,
196
- mkdir(CONFIG_DIR, {
197
- recursive: true
198
- })
183
+ resolveAuthOrConfigOptional()
199
184
  ];
200
185
  case 1:
201
- _state.sent();
202
- tmpPath = "".concat(CONFIG_PATH, ".tmp");
203
- return [
204
- 4,
205
- writeFile(tmpPath, "".concat(JSON.stringify(config, null, 2), "\n"), {
206
- mode: 384
207
- })
208
- ];
209
- case 2:
210
- _state.sent();
211
- return [
212
- 4,
213
- rename(tmpPath, CONFIG_PATH)
214
- ];
215
- case 3:
216
- _state.sent();
217
- return [
218
- 4,
219
- chmod(CONFIG_PATH, 384)
220
- ];
221
- case 4:
222
- _state.sent();
186
+ auth = _state.sent();
187
+ if (auth) {
188
+ return [
189
+ 2,
190
+ auth
191
+ ];
192
+ }
193
+ console.error('Not authenticated. Set DISPLAYDEV_API_KEY or run: dsp login');
194
+ process.exit(1);
223
195
  return [
224
196
  2
225
197
  ];
@@ -227,55 +199,34 @@ function saveConfig(config) {
227
199
  });
228
200
  })();
229
201
  }
230
- function resolveAuth() {
231
- var apiKey = process.env.DISPLAYDEV_API_KEY;
232
- if (apiKey) {
233
- var _process_env_DISPLAYDEV_API_URL;
234
- return {
235
- apiKey: apiKey,
236
- apiUrl: (_process_env_DISPLAYDEV_API_URL = process.env.DISPLAYDEV_API_URL) !== null && _process_env_DISPLAYDEV_API_URL !== void 0 ? _process_env_DISPLAYDEV_API_URL : DEFAULT_API_URL
237
- };
238
- }
239
- return null;
240
- }
241
- function resolveAuthOrConfig() {
202
+ /**
203
+ * Like `resolveAuthOrConfig()` but returns null instead of exiting when
204
+ * no credential is present. Used by flows that have a fallback (public
205
+ * publish) or a different behaviour without auth (MCP public-only tools).
206
+ */ function resolveAuthOrConfigOptional() {
242
207
  return _async_to_generator(function() {
243
- var env, config, _config_apiUrl;
208
+ var config;
244
209
  return _ts_generator(this, function(_state) {
245
210
  switch(_state.label){
246
211
  case 0:
247
- env = resolveAuth();
248
- if (env) {
249
- return [
250
- 2,
251
- env
252
- ];
253
- }
254
212
  return [
255
213
  4,
256
214
  loadConfig()
257
215
  ];
258
216
  case 1:
259
217
  config = _state.sent();
260
- if (config === null || config === void 0 ? void 0 : config.token) {
261
- ;
262
- return [
263
- 2,
264
- {
265
- apiKey: config.token,
266
- apiUrl: (_config_apiUrl = config.apiUrl) !== null && _config_apiUrl !== void 0 ? _config_apiUrl : DEFAULT_API_URL
267
- }
268
- ];
269
- }
270
- console.error('Not authenticated. Set DISPLAYDEV_API_KEY or run: dsp login');
271
- process.exit(1);
272
218
  return [
273
- 2
219
+ 2,
220
+ resolveAuthFromEnvAndConfig(process.env, config)
274
221
  ];
275
222
  }
276
223
  });
277
224
  })();
278
225
  }
226
+ function resolvePublicApiUrl() {
227
+ var _process_env_DISPLAYDEV_API_URL;
228
+ return (_process_env_DISPLAYDEV_API_URL = process.env.DISPLAYDEV_API_URL) !== null && _process_env_DISPLAYDEV_API_URL !== void 0 ? _process_env_DISPLAYDEV_API_URL : DEFAULT_API_URL;
229
+ }
279
230
  function createClient(auth) {
280
231
  return new ApiClient({
281
232
  baseUrl: auth.apiUrl,
@@ -287,57 +238,225 @@ var program = new Command().name('dsp').description('display.dev CLI — publish
287
238
  function collectEmails(value, prev) {
288
239
  return prev.concat(value);
289
240
  }
241
+ function parseShowBrandingOrExit(raw) {
242
+ try {
243
+ return parseShowBrandingFlag(raw);
244
+ } catch (err) {
245
+ if (_instanceof(err, InvalidFlagError)) {
246
+ console.error("Invalid ".concat(err.flag, ": ").concat(err.value, ". Use show, hide, or inherit."));
247
+ process.exit(1);
248
+ }
249
+ throw err;
250
+ }
251
+ }
290
252
  // --- publish ---
291
- program.command('publish <path>').description('Publish an HTML or Markdown file').option('--name <name>', 'Artifact display name').option('--id <shortId>', 'Update existing artifact (new version)').option('--public', 'Make artifact publicly accessible').option('--company', 'Restrict artifact to company auth (default for new artifacts)').option('--share <email>', 'Share with guest email (repeatable)', collectEmails, []).option('--clear-shares', 'Remove all guest email shares (update only)').option('--theme <theme>', 'Markdown theme (default: github)').action(function(filePath, opts) {
253
+ program.command('publish <path>').description('Publish an HTML or Markdown file. Use "-" to read from stdin (requires --id).').option('--name <name>', 'Artifact display name').option('--id <shortId>', 'Update existing artifact (new version)').option('--public', 'Make artifact publicly accessible (alias for --visibility public)').option('--company', 'Restrict artifact to company auth (alias for --visibility company)').option('--visibility <level>', 'public | company | private. "private" requires the Teams plan.').option('--share <email>', 'Add an email to sharedWith (repeatable; alias for --share-with)', collectEmails, []).option('--share-with <emails>', 'Comma-separated email list for sharedWith', function(val) {
254
+ return val.split(',').map(function(e) {
255
+ return e.trim();
256
+ }).filter(Boolean);
257
+ }).option('--clear-shares', 'Remove all sharedWith entries (update only)').option('--theme <theme>', 'Markdown theme (default: github)').option('--show-branding <mode>', 'display.dev bar override: show, hide, or inherit (paid plans only)').action(function(filePath, opts) {
292
258
  return _async_to_generator(function() {
293
- var auth, client, ext, content, format, visibility, share, result, verb;
259
+ var _opts_shareWith, showBranding, auth, fromStdin, format, content, inferClient, detail, err, msg, publicClient, publicResult, err1, msg1, client, visibility, mergedShare, share, result, err2, msg2, verb;
294
260
  return _ts_generator(this, function(_state) {
295
261
  switch(_state.label){
296
262
  case 0:
297
- if (!opts.id && !opts.name) {
298
- console.error('--name is required for new artifacts. Use --id to update an existing one.');
299
- process.exit(1);
263
+ showBranding = parseShowBrandingOrExit(opts.showBranding);
264
+ return [
265
+ 4,
266
+ resolveAuthOrConfigOptional()
267
+ ];
268
+ case 1:
269
+ auth = _state.sent();
270
+ fromStdin = filePath === '-';
271
+ if (fromStdin) {
272
+ // stdin path is for re-publishing existing artifacts (`dsp export | dsp
273
+ // publish --id <id> -`). Path-specific gates run first so the user gets
274
+ // a clear error before we touch the network or stdin.
275
+ if (!auth) {
276
+ console.error('Reading from stdin (-) requires auth. Run: dsp login');
277
+ process.exit(1);
278
+ }
279
+ if (!opts.id) {
280
+ console.error('Reading from stdin (-) requires --id <shortId>.');
281
+ process.exit(2);
282
+ }
283
+ if (process.stdin.isTTY) {
284
+ console.error('cannot read source from a TTY; pipe a file or use a path');
285
+ process.exit(2);
286
+ }
300
287
  }
301
- if (opts.public && opts.company) {
302
- console.error('Use --public or --company, not both.');
303
- process.exit(1);
288
+ try {
289
+ validatePublishArgs({
290
+ name: opts.name,
291
+ id: opts.id,
292
+ public: opts.public,
293
+ company: opts.company,
294
+ visibility: opts.visibility,
295
+ share: opts.share,
296
+ shareWith: opts.shareWith,
297
+ clearShares: opts.clearShares,
298
+ showBranding: opts.showBranding,
299
+ filePath: filePath,
300
+ authenticated: auth !== null,
301
+ fromStdin: fromStdin
302
+ });
303
+ } catch (err) {
304
+ if (_instanceof(err, PublishArgsError)) {
305
+ console.error(err.message);
306
+ process.exit(1);
307
+ }
308
+ throw err;
304
309
  }
305
- if (opts.clearShares && opts.share.length > 0) {
306
- console.error('Use --share or --clear-shares, not both.');
310
+ if (!fromStdin) return [
311
+ 3,
312
+ 7
313
+ ];
314
+ // The artifact's format is fixed at create — infer it via GET so the
315
+ // round-trip preserves it without making the caller pass --format.
316
+ inferClient = createClient(auth);
317
+ _state.label = 2;
318
+ case 2:
319
+ _state.trys.push([
320
+ 2,
321
+ 4,
322
+ ,
323
+ 5
324
+ ]);
325
+ return [
326
+ 4,
327
+ inferClient.get(opts.id)
328
+ ];
329
+ case 3:
330
+ detail = _state.sent();
331
+ format = detail.format === 'md' ? 'md' : 'html';
332
+ return [
333
+ 3,
334
+ 5
335
+ ];
336
+ case 4:
337
+ err = _state.sent();
338
+ if (_instanceof(err, ApiError) && (err.status === 401 || err.status === 403)) {
339
+ console.error('Your credential is no longer valid. Run: dsp login (or rotate DISPLAYDEV_API_KEY).');
307
340
  process.exit(1);
308
341
  }
309
- if (opts.clearShares && !opts.id) {
310
- console.error('--clear-shares only applies when updating (--id).');
311
- process.exit(1);
342
+ if (_instanceof(err, ApiError) && err.status === 404) {
343
+ console.error("Artifact not found: ".concat(opts.id));
344
+ process.exit(4);
312
345
  }
346
+ msg = _instanceof(err, Error) ? err.message : String(err);
347
+ console.error(msg);
348
+ process.exit(1);
349
+ return [
350
+ 3,
351
+ 5
352
+ ];
353
+ case 5:
313
354
  return [
314
355
  4,
315
- resolveAuthOrConfig()
356
+ readStreamToString(process.stdin)
316
357
  ];
317
- case 1:
318
- auth = _state.sent();
319
- client = createClient(auth);
320
- ext = extname(filePath).toLowerCase();
321
- if (ext !== '.html' && ext !== '.md') {
322
- console.error("Unsupported file type: ".concat(ext, " (expected .html or .md)"));
323
- process.exit(1);
324
- }
358
+ case 6:
359
+ content = _state.sent();
360
+ return [
361
+ 3,
362
+ 9
363
+ ];
364
+ case 7:
365
+ format = filePath.toLowerCase().endsWith('.md') ? 'md' : 'html';
325
366
  return [
326
367
  4,
327
368
  readFile(filePath, 'utf-8')
328
369
  ];
329
- case 2:
370
+ case 8:
330
371
  content = _state.sent();
331
- format = ext === '.md' ? 'md' : 'html';
332
- if (opts.public) {
372
+ _state.label = 9;
373
+ case 9:
374
+ if (!!auth) return [
375
+ 3,
376
+ 14
377
+ ];
378
+ publicClient = new ApiClient({
379
+ baseUrl: resolvePublicApiUrl(),
380
+ apiKey: '',
381
+ clientType: 'cli'
382
+ });
383
+ _state.label = 10;
384
+ case 10:
385
+ _state.trys.push([
386
+ 10,
387
+ 12,
388
+ ,
389
+ 13
390
+ ]);
391
+ return [
392
+ 4,
393
+ publicClient.publishPublic({
394
+ content: content,
395
+ name: opts.name,
396
+ format: format
397
+ })
398
+ ];
399
+ case 11:
400
+ publicResult = _state.sent();
401
+ return [
402
+ 3,
403
+ 13
404
+ ];
405
+ case 12:
406
+ err1 = _state.sent();
407
+ msg1 = _instanceof(err1, Error) ? err1.message : String(err1);
408
+ console.error(msg1);
409
+ process.exit(1);
410
+ return [
411
+ 3,
412
+ 13
413
+ ];
414
+ case 13:
415
+ // Full response as JSON on stdout so `dsp publish … | jq -r .previewUrl`
416
+ // works alongside the human-readable block on stderr.
417
+ console.log(JSON.stringify(publicResult));
418
+ process.stderr.write([
419
+ '',
420
+ "Published anonymously — nobody owns this artifact yet.",
421
+ " Preview: ".concat(publicResult.previewUrl),
422
+ " Claim: ".concat(publicResult.claimUrl),
423
+ " Expires: ".concat(publicResult.expiresAt),
424
+ "Sign in at the claim URL to move it into your display.dev organization.",
425
+ ''
426
+ ].join('\n'));
427
+ return [
428
+ 2
429
+ ];
430
+ case 14:
431
+ // --- Authenticated path — `--id` is update, otherwise create. ---
432
+ client = createClient(auth);
433
+ if (opts.visibility) {
434
+ if (opts.visibility !== 'public' && opts.visibility !== 'company' && opts.visibility !== 'private') {
435
+ console.error("Invalid --visibility: ".concat(opts.visibility, ". Use public, company, or private."));
436
+ process.exit(1);
437
+ }
438
+ visibility = opts.visibility;
439
+ } else if (opts.public) {
333
440
  visibility = 'public';
334
441
  } else if (opts.company) {
335
442
  visibility = 'company';
336
443
  }
337
- share = opts.share.length > 0 ? opts.share : undefined;
444
+ // --share-with (csv) and --share (repeatable) both contribute to the
445
+ // sharedWith list. Concatenating rather than making them mutually
446
+ // exclusive keeps CLI composition simple for scripts that want to mix.
447
+ mergedShare = _to_consumable_array((_opts_shareWith = opts.shareWith) !== null && _opts_shareWith !== void 0 ? _opts_shareWith : []).concat(_to_consumable_array(opts.share));
448
+ share = mergedShare.length > 0 ? mergedShare : undefined;
449
+ _state.label = 15;
450
+ case 15:
451
+ _state.trys.push([
452
+ 15,
453
+ 20,
454
+ ,
455
+ 21
456
+ ]);
338
457
  if (!opts.id) return [
339
458
  3,
340
- 4
459
+ 17
341
460
  ];
342
461
  return [
343
462
  4,
@@ -348,16 +467,17 @@ program.command('publish <path>').description('Publish an HTML or Markdown file'
348
467
  theme: opts.theme,
349
468
  share: share,
350
469
  clearShares: opts.clearShares,
351
- visibility: visibility
470
+ visibility: visibility,
471
+ showBranding: showBranding
352
472
  })
353
473
  ];
354
- case 3:
474
+ case 16:
355
475
  result = _state.sent();
356
476
  return [
357
477
  3,
358
- 6
478
+ 19
359
479
  ];
360
- case 4:
480
+ case 17:
361
481
  return [
362
482
  4,
363
483
  client.publish({
@@ -366,13 +486,38 @@ program.command('publish <path>').description('Publish an HTML or Markdown file'
366
486
  format: format,
367
487
  theme: opts.theme,
368
488
  share: share,
369
- visibility: visibility
489
+ visibility: visibility,
490
+ showBranding: showBranding
370
491
  })
371
492
  ];
372
- case 5:
493
+ case 18:
373
494
  result = _state.sent();
374
- _state.label = 6;
375
- case 6:
495
+ _state.label = 19;
496
+ case 19:
497
+ return [
498
+ 3,
499
+ 21
500
+ ];
501
+ case 20:
502
+ err2 = _state.sent();
503
+ // Fail closed on an expired / revoked credential: do NOT fall through
504
+ // to the public endpoint, since the user intended a workspace publish.
505
+ if (_instanceof(err2, ApiError) && (err2.status === 401 || err2.status === 403)) {
506
+ console.error('Your credential is no longer valid. Run: dsp login (or rotate DISPLAYDEV_API_KEY).');
507
+ process.exit(1);
508
+ }
509
+ msg2 = _instanceof(err2, Error) ? err2.message : String(err2);
510
+ if (classifyBrandingError(msg2) === 'paid-plan') {
511
+ console.error('Error: Hiding display.dev branding requires a paid plan. See https://display.dev/billing');
512
+ } else {
513
+ console.error(msg2);
514
+ }
515
+ process.exit(1);
516
+ return [
517
+ 3,
518
+ 21
519
+ ];
520
+ case 21:
376
521
  console.log(result.url);
377
522
  verb = opts.id ? 'Updated' : 'Published';
378
523
  console.log("".concat(verb, " ").concat(result.name, " (").concat(result.shortId, ") v").concat(result.version));
@@ -383,6 +528,96 @@ program.command('publish <path>').description('Publish an HTML or Markdown file'
383
528
  });
384
529
  })();
385
530
  });
531
+ // --- share ---
532
+ program.command('share <shortId>').description('Change an artifact\'s visibility and/or add/remove shared-with emails.').option('--visibility <level>', 'public | company | private. "private" requires the Teams plan.').option('--add-users <emails>', 'Comma-separated emails to add to sharedWith', function(val) {
533
+ return val.split(',').map(function(e) {
534
+ return e.trim();
535
+ }).filter(Boolean);
536
+ }).option('--remove-users <emails>', 'Comma-separated emails to remove from sharedWith', function(val) {
537
+ return val.split(',').map(function(e) {
538
+ return e.trim();
539
+ }).filter(Boolean);
540
+ }).action(function(shortId, opts) {
541
+ return _async_to_generator(function() {
542
+ var auth, client, result, err, msg;
543
+ return _ts_generator(this, function(_state) {
544
+ switch(_state.label){
545
+ case 0:
546
+ if (opts.visibility === undefined && (!opts.addUsers || opts.addUsers.length === 0) && (!opts.removeUsers || opts.removeUsers.length === 0)) {
547
+ console.error('Provide at least one of --visibility, --add-users, --remove-users.');
548
+ process.exit(1);
549
+ }
550
+ if (opts.visibility !== undefined && opts.visibility !== 'public' && opts.visibility !== 'company' && opts.visibility !== 'private') {
551
+ console.error("Invalid --visibility: ".concat(opts.visibility, ". Use public, company, or private."));
552
+ process.exit(1);
553
+ }
554
+ return [
555
+ 4,
556
+ resolveAuthOrConfig()
557
+ ];
558
+ case 1:
559
+ auth = _state.sent();
560
+ client = createClient(auth);
561
+ _state.label = 2;
562
+ case 2:
563
+ _state.trys.push([
564
+ 2,
565
+ 4,
566
+ ,
567
+ 5
568
+ ]);
569
+ return [
570
+ 4,
571
+ client.share(shortId, {
572
+ visibility: opts.visibility,
573
+ addUsers: opts.addUsers,
574
+ removeUsers: opts.removeUsers
575
+ })
576
+ ];
577
+ case 3:
578
+ result = _state.sent();
579
+ console.log(JSON.stringify(result, null, 2));
580
+ return [
581
+ 3,
582
+ 5
583
+ ];
584
+ case 4:
585
+ err = _state.sent();
586
+ if (_instanceof(err, ApiError) && err.status === 402) {
587
+ console.error('Error: Private visibility requires the Teams plan. Upgrade at https://display.dev/pricing');
588
+ process.exit(1);
589
+ }
590
+ if (_instanceof(err, ApiError) && err.status === 404) {
591
+ console.error("Artifact not found: ".concat(shortId));
592
+ process.exit(4);
593
+ }
594
+ if (_instanceof(err, ApiError) && err.status === 401) {
595
+ // 401 is always "credential expired / revoked" — sessions + api keys
596
+ // both return it on an invalid secret. 403 is authorization ("you're
597
+ // signed in but not allowed"), which we surface with the API's own
598
+ // message below.
599
+ console.error('Your credential is no longer valid. Run: dsp login (or rotate DISPLAYDEV_API_KEY).');
600
+ process.exit(1);
601
+ }
602
+ if (_instanceof(err, ApiError) && (err.status === 400 || err.status === 403)) {
603
+ console.error(err.message);
604
+ process.exit(1);
605
+ }
606
+ msg = _instanceof(err, Error) ? err.message : String(err);
607
+ console.error(msg);
608
+ process.exit(1);
609
+ return [
610
+ 3,
611
+ 5
612
+ ];
613
+ case 5:
614
+ return [
615
+ 2
616
+ ];
617
+ }
618
+ });
619
+ })();
620
+ });
386
621
  // --- find ---
387
622
  program.command('find [query]').description('Search for artifacts').option('--by <email>', 'Filter by publisher email').option('--mine', 'Show only artifacts you published').option('--since <date>', 'Filter by date (ISO format)').option('--sort <col>', 'Sort column: updated_at, view_count, name', 'updated_at').option('--dir <direction>', 'Sort direction: asc or desc').option('--limit <n>', 'Max rows to fetch (1-100)', function(v) {
388
623
  return parseInt(v, 10);
@@ -458,13 +693,46 @@ program.command('find [query]').description('Search for artifacts').option('--by
458
693
  });
459
694
  })();
460
695
  });
461
- // --- get ---
462
- program.command('get <shortId>').description('Get artifact details').option('--include <field>', 'Include additional data (repeatable, e.g. versions)', collectEmails, []).action(function(shortId, opts) {
696
+ // --- get ---
697
+ program.command('get <shortId>').description('Get artifact details').option('--include <field>', 'Include additional data (repeatable, e.g. versions)', collectEmails, []).action(function(shortId, opts) {
698
+ return _async_to_generator(function() {
699
+ var auth, client, result;
700
+ return _ts_generator(this, function(_state) {
701
+ switch(_state.label){
702
+ case 0:
703
+ return [
704
+ 4,
705
+ resolveAuthOrConfig()
706
+ ];
707
+ case 1:
708
+ auth = _state.sent();
709
+ client = createClient(auth);
710
+ return [
711
+ 4,
712
+ client.get(shortId, opts.include.length > 0 ? opts.include : undefined)
713
+ ];
714
+ case 2:
715
+ result = _state.sent();
716
+ console.log(JSON.stringify(result, null, 2));
717
+ return [
718
+ 2
719
+ ];
720
+ }
721
+ });
722
+ })();
723
+ });
724
+ // --- export ---
725
+ program.command('export <shortId>').description('Print the published source bytes to stdout. Pin a version with @<n>.').action(function(shortIdArg) {
463
726
  return _async_to_generator(function() {
464
- var auth, client, result;
727
+ var parsed, auth, client, result, err, msg;
465
728
  return _ts_generator(this, function(_state) {
466
729
  switch(_state.label){
467
730
  case 0:
731
+ parsed = parseShortIdAndVersion(shortIdArg);
732
+ if (!parsed) {
733
+ console.error('Invalid argument. Expected <shortId> or <shortId>@<version> (version must be a positive integer).');
734
+ process.exit(2);
735
+ }
468
736
  return [
469
737
  4,
470
738
  resolveAuthOrConfig()
@@ -472,13 +740,50 @@ program.command('get <shortId>').description('Get artifact details').option('--i
472
740
  case 1:
473
741
  auth = _state.sent();
474
742
  client = createClient(auth);
743
+ _state.label = 2;
744
+ case 2:
745
+ _state.trys.push([
746
+ 2,
747
+ 4,
748
+ ,
749
+ 5
750
+ ]);
475
751
  return [
476
752
  4,
477
- client.get(shortId, opts.include.length > 0 ? opts.include : undefined)
753
+ client.exportSource(parsed.shortId, parsed.version)
478
754
  ];
479
- case 2:
755
+ case 3:
480
756
  result = _state.sent();
481
- console.log(JSON.stringify(result, null, 2));
757
+ return [
758
+ 3,
759
+ 5
760
+ ];
761
+ case 4:
762
+ err = _state.sent();
763
+ if (_instanceof(err, ApiError)) {
764
+ if (err.status === 404) {
765
+ console.error('Artifact not found');
766
+ process.exit(4);
767
+ }
768
+ if (err.status === 403) {
769
+ console.error('Forbidden');
770
+ process.exit(4);
771
+ }
772
+ if (err.status === 401) {
773
+ console.error('Your credential is no longer valid. Run: dsp login (or rotate DISPLAYDEV_API_KEY).');
774
+ process.exit(1);
775
+ }
776
+ }
777
+ msg = _instanceof(err, Error) ? err.message : String(err);
778
+ console.error(msg);
779
+ process.exit(1);
780
+ return [
781
+ 3,
782
+ 5
783
+ ];
784
+ case 5:
785
+ // Binary-clean: write Buffer directly, no console.log (which appends \n).
786
+ process.stdout.write(result.data);
482
787
  return [
483
788
  2
484
789
  ];
@@ -519,6 +824,9 @@ program.command('delete <shortId>').description('Delete an artifact permanently'
519
824
  })();
520
825
  });
521
826
  function openBrowser(url) {
827
+ if (process.env.DISPLAYDEV_SKIP_BROWSER) {
828
+ return;
829
+ }
522
830
  try {
523
831
  var os = platform();
524
832
  if (os === 'darwin') {
@@ -542,15 +850,10 @@ function openBrowser(url) {
542
850
  // URL is already printed — user can open it manually
543
851
  }
544
852
  }
545
- function sleep(ms) {
546
- return new Promise(function(resolve) {
547
- return setTimeout(resolve, ms);
548
- });
549
- }
550
853
  // --- login ---
551
854
  program.command('login').description('Authenticate with display.dev').option('--email <email>', 'Email address').option('--code <code>', 'OTP code (verify step; pair with --email)').option('--api-key [key]', 'Authenticate with an API key').option('--json', 'Machine-readable output (structured status, no prose)').action(function(opts) {
552
855
  return _async_to_generator(function() {
553
- var _process_env_DISPLAYDEV_API_URL, emit, emitErr, apiUrl, client, key, rl, validation, email, rl1, method, check, unused, err, msg, code, rl2, result, unused1, deviceResult, unused2, device_code, verification_uri_complete, initialInterval, interval, tokenResult, unused3, _$err;
856
+ var _process_env_DISPLAYDEV_API_URL, emit, emitErr, apiUrl, client, key, unused, rl, validation, email, rl1, method, check, unused1, err, msg, code, rl2, result, unused2, deviceResult, unused3, device_code, verification_uri_complete, initialInterval, expires_in, token, err1;
554
857
  return _ts_generator(this, function(_state) {
555
858
  switch(_state.label){
556
859
  case 0:
@@ -578,7 +881,7 @@ program.command('login').description('Authenticate with display.dev').option('--
578
881
  });
579
882
  if (!(opts.apiKey !== undefined)) return [
580
883
  3,
581
- 8
884
+ 11
582
885
  ];
583
886
  if (!(typeof opts.apiKey === 'string')) return [
584
887
  3,
@@ -587,54 +890,46 @@ program.command('login').description('Authenticate with display.dev').option('--
587
890
  key = opts.apiKey;
588
891
  return [
589
892
  3,
590
- 5
893
+ 8
591
894
  ];
592
895
  case 1:
593
896
  if (!process.stdin.isTTY) return [
594
897
  3,
595
- 3
898
+ 6
596
899
  ];
597
- // Mask input for interactive API key entry
900
+ // Raw-mode input suppresses terminal echo.
598
901
  process.stdout.write('API key: ');
902
+ _state.label = 2;
903
+ case 2:
904
+ _state.trys.push([
905
+ 2,
906
+ 4,
907
+ ,
908
+ 5
909
+ ]);
599
910
  return [
600
911
  4,
601
- new Promise(function(resolve) {
602
- var input = '';
603
- process.stdin.setRawMode(true);
604
- process.stdin.resume();
605
- process.stdin.setEncoding('utf8');
606
- var cleanup = function cleanup() {
607
- process.stdin.setRawMode(false);
608
- process.stdin.pause();
609
- process.stdin.removeListener('data', onData);
610
- };
611
- var onData = function onData(ch) {
612
- if (ch === '\r' || ch === '\n') {
613
- cleanup();
614
- process.stdout.write('\n');
615
- resolve(input);
616
- } else if (ch === '\u0003') {
617
- cleanup();
618
- process.stdout.write('\n');
619
- process.exit(1);
620
- } else if (ch === '\u007F' || ch === '\b') {
621
- if (input.length > 0) {
622
- input = input.slice(0, -1);
623
- }
624
- } else {
625
- input += ch;
626
- }
627
- };
628
- process.stdin.on('data', onData);
629
- })
912
+ readApiKeyFromTty(process.stdin, process.stdout)
630
913
  ];
631
- case 2:
914
+ case 3:
632
915
  key = _state.sent();
633
916
  return [
634
917
  3,
635
918
  5
636
919
  ];
637
- case 3:
920
+ case 4:
921
+ unused = _state.sent();
922
+ process.exit(1);
923
+ return [
924
+ 3,
925
+ 5
926
+ ];
927
+ case 5:
928
+ return [
929
+ 3,
930
+ 8
931
+ ];
932
+ case 6:
638
933
  // Non-TTY: read from stdin (piped input)
639
934
  rl = createInterface({
640
935
  input: process.stdin,
@@ -644,11 +939,11 @@ program.command('login').description('Authenticate with display.dev').option('--
644
939
  4,
645
940
  rl.question('API key: ')
646
941
  ];
647
- case 4:
942
+ case 7:
648
943
  key = _state.sent();
649
944
  rl.close();
650
- _state.label = 5;
651
- case 5:
945
+ _state.label = 8;
946
+ case 8:
652
947
  key = key.trim();
653
948
  if (!key) {
654
949
  console.error('API key cannot be empty.');
@@ -658,7 +953,7 @@ program.command('login').description('Authenticate with display.dev').option('--
658
953
  4,
659
954
  client.validateApiKey(key)
660
955
  ];
661
- case 6:
956
+ case 9:
662
957
  validation = _state.sent();
663
958
  if (validation === 'invalid') {
664
959
  emitErr('Invalid API key. Check the key and try again.', {
@@ -677,7 +972,7 @@ program.command('login').description('Authenticate with display.dev').option('--
677
972
  apiUrl: apiUrl
678
973
  })
679
974
  ];
680
- case 7:
975
+ case 10:
681
976
  _state.sent();
682
977
  emit('Authenticated.', {
683
978
  status: 'authenticated',
@@ -686,12 +981,12 @@ program.command('login').description('Authenticate with display.dev').option('--
686
981
  return [
687
982
  2
688
983
  ];
689
- case 8:
984
+ case 11:
690
985
  // --- Mode 1 & 2: Email-based login ---
691
986
  email = opts.email;
692
987
  if (!!email) return [
693
988
  3,
694
- 10
989
+ 13
695
990
  ];
696
991
  if (!process.stdin.isTTY) {
697
992
  console.error('Email is required. Use --email <email> for non-interactive mode.');
@@ -705,67 +1000,67 @@ program.command('login').description('Authenticate with display.dev').option('--
705
1000
  4,
706
1001
  rl1.question('Email: ')
707
1002
  ];
708
- case 9:
1003
+ case 12:
709
1004
  email = _state.sent();
710
1005
  rl1.close();
711
- _state.label = 10;
712
- case 10:
1006
+ _state.label = 13;
1007
+ case 13:
713
1008
  email = email.trim();
714
1009
  // Check auth method
715
1010
  method = 'otp';
716
- _state.label = 11;
717
- case 11:
1011
+ _state.label = 14;
1012
+ case 14:
718
1013
  _state.trys.push([
719
- 11,
720
- 13,
1014
+ 14,
1015
+ 16,
721
1016
  ,
722
- 14
1017
+ 17
723
1018
  ]);
724
1019
  return [
725
1020
  4,
726
1021
  client.authCheck(email)
727
1022
  ];
728
- case 12:
1023
+ case 15:
729
1024
  check = _state.sent();
730
1025
  method = check.method;
731
1026
  return [
732
1027
  3,
733
- 14
1028
+ 17
734
1029
  ];
735
- case 13:
736
- unused = _state.sent();
1030
+ case 16:
1031
+ unused1 = _state.sent();
737
1032
  return [
738
1033
  3,
739
- 14
1034
+ 17
740
1035
  ];
741
- case 14:
1036
+ case 17:
742
1037
  if (!(method === 'otp')) return [
743
1038
  3,
744
- 27
1039
+ 30
745
1040
  ];
746
1041
  if (!!opts.code) return [
747
1042
  3,
748
- 19
1043
+ 22
749
1044
  ];
750
- _state.label = 15;
751
- case 15:
1045
+ _state.label = 18;
1046
+ case 18:
752
1047
  _state.trys.push([
753
- 15,
754
- 17,
1048
+ 18,
1049
+ 20,
755
1050
  ,
756
- 18
1051
+ 21
757
1052
  ]);
758
1053
  return [
759
1054
  4,
760
1055
  client.sendOtp(email)
761
1056
  ];
762
- case 16:
1057
+ case 19:
763
1058
  _state.sent();
764
1059
  return [
765
1060
  3,
766
- 18
1061
+ 21
767
1062
  ];
768
- case 17:
1063
+ case 20:
769
1064
  err = _state.sent();
770
1065
  msg = _instanceof(err, Error) ? err.message : 'Something went wrong';
771
1066
  if (msg.includes('requires SSO')) {
@@ -782,9 +1077,9 @@ program.command('login').description('Authenticate with display.dev').option('--
782
1077
  process.exit(1);
783
1078
  return [
784
1079
  3,
785
- 18
1080
+ 21
786
1081
  ];
787
- case 18:
1082
+ case 21:
788
1083
  if (!process.stdin.isTTY) {
789
1084
  // Non-interactive: exit after sending. The caller (typically an
790
1085
  // agent) will collect the OTP from the user and re-invoke with --code.
@@ -814,18 +1109,18 @@ program.command('login').description('Authenticate with display.dev').option('--
814
1109
  if (!opts.json) {
815
1110
  console.log("Code sent to ".concat(email));
816
1111
  }
817
- _state.label = 19;
818
- case 19:
1112
+ _state.label = 22;
1113
+ case 22:
819
1114
  if (!opts.code) return [
820
1115
  3,
821
- 20
1116
+ 23
822
1117
  ];
823
1118
  code = opts.code;
824
1119
  return [
825
1120
  3,
826
- 22
1121
+ 25
827
1122
  ];
828
- case 20:
1123
+ case 23:
829
1124
  rl2 = createInterface({
830
1125
  input: process.stdin,
831
1126
  output: process.stdout
@@ -834,22 +1129,22 @@ program.command('login').description('Authenticate with display.dev').option('--
834
1129
  4,
835
1130
  rl2.question('Enter the 6-digit code: ')
836
1131
  ];
837
- case 21:
1132
+ case 24:
838
1133
  code = _state.sent();
839
1134
  rl2.close();
840
- _state.label = 22;
841
- case 22:
1135
+ _state.label = 25;
1136
+ case 25:
842
1137
  _state.trys.push([
843
- 22,
844
1138
  25,
1139
+ 28,
845
1140
  ,
846
- 26
1141
+ 29
847
1142
  ]);
848
1143
  return [
849
1144
  4,
850
1145
  client.verifyOtp(email, code.trim())
851
1146
  ];
852
- case 23:
1147
+ case 26:
853
1148
  result = _state.sent();
854
1149
  return [
855
1150
  4,
@@ -858,7 +1153,7 @@ program.command('login').description('Authenticate with display.dev').option('--
858
1153
  apiUrl: apiUrl
859
1154
  })
860
1155
  ];
861
- case 24:
1156
+ case 27:
862
1157
  _state.sent();
863
1158
  emit("Logged in as ".concat(email), {
864
1159
  status: 'authenticated',
@@ -867,10 +1162,10 @@ program.command('login').description('Authenticate with display.dev').option('--
867
1162
  });
868
1163
  return [
869
1164
  3,
870
- 26
1165
+ 29
871
1166
  ];
872
- case 25:
873
- unused1 = _state.sent();
1167
+ case 28:
1168
+ unused2 = _state.sent();
874
1169
  emitErr('Invalid or expired code. Try again.', {
875
1170
  status: 'error',
876
1171
  error: 'invalid_or_expired_code'
@@ -878,142 +1173,157 @@ program.command('login').description('Authenticate with display.dev').option('--
878
1173
  process.exit(1);
879
1174
  return [
880
1175
  3,
881
- 26
1176
+ 29
882
1177
  ];
883
- case 26:
1178
+ case 29:
884
1179
  return [
885
1180
  3,
886
- 40
1181
+ 39
887
1182
  ];
888
- case 27:
1183
+ case 30:
889
1184
  // --- Mode 2: SSO device flow ---
890
1185
  console.log('Your organization requires SSO. Opening browser...');
891
- _state.label = 28;
892
- case 28:
1186
+ _state.label = 31;
1187
+ case 31:
893
1188
  _state.trys.push([
894
- 28,
895
- 30,
1189
+ 31,
1190
+ 33,
896
1191
  ,
897
- 31
1192
+ 34
898
1193
  ]);
899
1194
  return [
900
1195
  4,
901
1196
  client.requestDeviceCode('dsp-cli')
902
1197
  ];
903
- case 29:
1198
+ case 32:
904
1199
  deviceResult = _state.sent();
905
1200
  return [
906
1201
  3,
907
- 31
1202
+ 34
908
1203
  ];
909
- case 30:
910
- unused2 = _state.sent();
1204
+ case 33:
1205
+ unused3 = _state.sent();
911
1206
  console.error('Something went wrong. Check your connection and try again.');
912
1207
  process.exit(1);
913
1208
  return [
914
1209
  3,
915
- 31
1210
+ 34
916
1211
  ];
917
- case 31:
918
- device_code = deviceResult.device_code, verification_uri_complete = deviceResult.verification_uri_complete, initialInterval = deviceResult.interval;
1212
+ case 34:
1213
+ device_code = deviceResult.device_code, verification_uri_complete = deviceResult.verification_uri_complete, initialInterval = deviceResult.interval, expires_in = deviceResult.expires_in;
919
1214
  console.log();
920
1215
  console.log(" ".concat(verification_uri_complete));
921
1216
  console.log();
922
1217
  openBrowser(verification_uri_complete);
923
- // Poll for token
924
- interval = (initialInterval || 5) * 1000;
925
1218
  process.stdout.write('Waiting for authentication...');
926
- _state.label = 32;
927
- case 32:
928
- if (!true) return [
929
- 3,
930
- 40
931
- ];
932
- return [
933
- 4,
934
- sleep(interval)
935
- ];
936
- case 33:
937
- _state.sent();
938
- tokenResult = void 0;
939
- _state.label = 34;
940
- case 34:
1219
+ _state.label = 35;
1220
+ case 35:
941
1221
  _state.trys.push([
942
- 34,
943
- 36,
1222
+ 35,
1223
+ 38,
944
1224
  ,
945
- 37
1225
+ 39
946
1226
  ]);
947
1227
  return [
948
1228
  4,
949
- client.pollDeviceToken(device_code, 'dsp-cli')
950
- ];
951
- case 35:
952
- tokenResult = _state.sent();
953
- return [
954
- 3,
955
- 37
1229
+ pollDeviceToken(client, device_code, 'dsp-cli', {
1230
+ intervalMs: (initialInterval || 5) * 1000,
1231
+ expiresAt: Date.now() + (expires_in || 600) * 1000
1232
+ })
956
1233
  ];
957
1234
  case 36:
958
- unused3 = _state.sent();
959
- // Transient network error — retry on next interval
960
- return [
961
- 3,
962
- 32
963
- ];
964
- case 37:
965
- if (!('access_token' in tokenResult)) return [
966
- 3,
967
- 39
968
- ];
1235
+ token = _state.sent();
969
1236
  console.log(' done');
970
1237
  return [
971
1238
  4,
972
1239
  saveConfig({
973
- token: tokenResult.access_token,
1240
+ token: token,
974
1241
  apiUrl: apiUrl
975
1242
  })
976
1243
  ];
977
- case 38:
1244
+ case 37:
978
1245
  _state.sent();
979
1246
  console.log("Logged in as ".concat(email));
980
1247
  return [
981
1248
  2
982
1249
  ];
983
- case 39:
984
- _$err = tokenResult;
985
- if (_$err.error === 'authorization_pending') {
986
- return [
987
- 3,
988
- 32
989
- ];
990
- }
991
- if (_$err.error === 'slow_down') {
992
- interval += 5000;
993
- return [
994
- 3,
995
- 32
996
- ];
997
- }
998
- if (_$err.error === 'access_denied') {
999
- console.log();
1250
+ case 38:
1251
+ err1 = _state.sent();
1252
+ console.log();
1253
+ if (_instanceof(err1, DeviceCodeDeniedError)) {
1000
1254
  console.error('Authentication denied. Run dsp login to try again.');
1001
- process.exit(1);
1002
- }
1003
- if (_$err.error === 'expired_token') {
1004
- console.log();
1255
+ } else if (_instanceof(err1, DeviceCodeExpiredError)) {
1005
1256
  console.error('Code expired. Run dsp login to try again.');
1257
+ } else if (_instanceof(err1, DeviceCodeFailedError)) {
1258
+ console.error(err1.message || 'Authentication failed. Run dsp login to try again.');
1259
+ } else {
1260
+ console.error('Authentication failed. Run dsp login to try again.');
1261
+ }
1262
+ process.exit(1);
1263
+ return [
1264
+ 3,
1265
+ 39
1266
+ ];
1267
+ case 39:
1268
+ return [
1269
+ 2
1270
+ ];
1271
+ }
1272
+ });
1273
+ })();
1274
+ });
1275
+ // --- branding ---
1276
+ program.command('branding <shortId> <mode>').description('Override display.dev branding for an existing artifact without re-publishing (show|hide|inherit)').action(function(shortId, modeRaw) {
1277
+ return _async_to_generator(function() {
1278
+ var mode, auth, client, result, err, msg;
1279
+ return _ts_generator(this, function(_state) {
1280
+ switch(_state.label){
1281
+ case 0:
1282
+ mode = parseShowBrandingOrExit(modeRaw);
1283
+ if (!mode) {
1284
+ console.error('mode is required');
1006
1285
  process.exit(1);
1007
1286
  }
1008
- // Unknown error
1009
- console.log();
1010
- console.error(_$err.error_description || 'Authentication failed. Run dsp login to try again.');
1287
+ return [
1288
+ 4,
1289
+ resolveAuthOrConfig()
1290
+ ];
1291
+ case 1:
1292
+ auth = _state.sent();
1293
+ client = createClient(auth);
1294
+ _state.label = 2;
1295
+ case 2:
1296
+ _state.trys.push([
1297
+ 2,
1298
+ 4,
1299
+ ,
1300
+ 5
1301
+ ]);
1302
+ return [
1303
+ 4,
1304
+ client.setArtifactBranding(shortId, mode)
1305
+ ];
1306
+ case 3:
1307
+ result = _state.sent();
1308
+ console.log("".concat(result.shortId, " branding=").concat(result.showBranding === null ? 'inherit' : result.showBranding ? 'show' : 'hide'));
1309
+ return [
1310
+ 3,
1311
+ 5
1312
+ ];
1313
+ case 4:
1314
+ err = _state.sent();
1315
+ msg = _instanceof(err, Error) ? err.message : String(err);
1316
+ if (classifyBrandingError(msg) === 'paid-plan') {
1317
+ console.error('Error: Hiding display.dev branding requires a paid plan. See https://display.dev/billing');
1318
+ } else {
1319
+ console.error(msg);
1320
+ }
1011
1321
  process.exit(1);
1012
1322
  return [
1013
1323
  3,
1014
- 32
1324
+ 5
1015
1325
  ];
1016
- case 40:
1326
+ case 5:
1017
1327
  return [
1018
1328
  2
1019
1329
  ];
@@ -1024,16 +1334,20 @@ program.command('login').description('Authenticate with display.dev').option('--
1024
1334
  // --- mcp ---
1025
1335
  program.command('mcp').description('Start MCP server over stdin/stdout').action(function() {
1026
1336
  return _async_to_generator(function() {
1027
- var auth, client;
1337
+ var auth, client, publicClient;
1028
1338
  return _ts_generator(this, function(_state) {
1029
1339
  switch(_state.label){
1030
1340
  case 0:
1031
1341
  return [
1032
1342
  4,
1033
- resolveAuthOrConfig()
1343
+ resolveAuthOrConfigOptional()
1034
1344
  ];
1035
1345
  case 1:
1036
1346
  auth = _state.sent();
1347
+ if (!auth) return [
1348
+ 3,
1349
+ 3
1350
+ ];
1037
1351
  client = new ApiClient({
1038
1352
  baseUrl: auth.apiUrl,
1039
1353
  apiKey: auth.apiKey,
@@ -1048,6 +1362,28 @@ program.command('mcp').description('Start MCP server over stdin/stdout').action(
1048
1362
  return [
1049
1363
  2
1050
1364
  ];
1365
+ case 3:
1366
+ // Unauthenticated: expose only `publish`, which maps to the public
1367
+ // claimable endpoint and returns a claim URL the user visits to own
1368
+ // the artifact. Workspace-bound tools are not registered — they have
1369
+ // no meaningful behaviour without auth and listing them would invite
1370
+ // agents to call them and error out.
1371
+ publicClient = new ApiClient({
1372
+ baseUrl: resolvePublicApiUrl(),
1373
+ apiKey: '',
1374
+ clientType: 'mcp-stdio'
1375
+ });
1376
+ return [
1377
+ 4,
1378
+ startMcpServer(publicClient, {
1379
+ mode: 'public'
1380
+ })
1381
+ ];
1382
+ case 4:
1383
+ _state.sent();
1384
+ return [
1385
+ 2
1386
+ ];
1051
1387
  }
1052
1388
  });
1053
1389
  })();