@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.
@@ -27,6 +27,14 @@ function _async_to_generator(fn) {
27
27
  });
28
28
  };
29
29
  }
30
+ function _instanceof(left, right) {
31
+ "@swc/helpers - instanceof";
32
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
33
+ return !!right[Symbol.hasInstance](left);
34
+ } else {
35
+ return left instanceof right;
36
+ }
37
+ }
30
38
  function _ts_generator(thisArg, body) {
31
39
  var f, y, t, _ = {
32
40
  label: 0,
@@ -131,21 +139,88 @@ import { resolve } from 'node:path';
131
139
  import { z } from 'zod';
132
140
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
133
141
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
142
+ import { ApiError } from './api-client.js';
143
+ var FILE_ERROR_CODES = new Set([
144
+ 'ENOENT',
145
+ 'EACCES',
146
+ 'EISDIR',
147
+ 'ENOTDIR',
148
+ 'EMFILE'
149
+ ]);
150
+ function isFileError(err) {
151
+ if (!_instanceof(err, Error)) {
152
+ return false;
153
+ }
154
+ var code = err.code;
155
+ return typeof code === 'string' && FILE_ERROR_CODES.has(code);
156
+ }
157
+ function errorResponse(err) {
158
+ var body;
159
+ if (_instanceof(err, ApiError)) {
160
+ body = {
161
+ error: 'request_failed',
162
+ message: err.message,
163
+ status: err.status
164
+ };
165
+ } else if (isFileError(err)) {
166
+ body = {
167
+ error: 'file_error',
168
+ code: err.code,
169
+ message: err.message
170
+ };
171
+ } else {
172
+ var message = _instanceof(err, Error) ? err.message : String(err);
173
+ body = {
174
+ error: 'request_failed',
175
+ message: message
176
+ };
177
+ }
178
+ return {
179
+ content: [
180
+ {
181
+ type: 'text',
182
+ text: JSON.stringify(body)
183
+ }
184
+ ],
185
+ isError: true
186
+ };
187
+ }
188
+ function okResponse(result) {
189
+ return {
190
+ content: [
191
+ {
192
+ type: 'text',
193
+ text: JSON.stringify(result)
194
+ }
195
+ ]
196
+ };
197
+ }
134
198
  /**
135
199
  * Starts an MCP server over stdin/stdout.
136
200
  * Tools call the display.dev REST API via the ApiClient.
137
- */ export function startMcpServer(apiClient) {
138
- return _async_to_generator(function() {
139
- var server, transport;
201
+ */ export function startMcpServer(_0) {
202
+ return _async_to_generator(function(apiClient) {
203
+ var options, _options_mode, _options_transport, mode, server, transport;
204
+ var _arguments = arguments;
140
205
  return _ts_generator(this, function(_state) {
141
206
  switch(_state.label){
142
207
  case 0:
208
+ options = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
209
+ mode = (_options_mode = options.mode) !== null && _options_mode !== void 0 ? _options_mode : 'authenticated';
143
210
  server = new McpServer({
144
211
  name: 'display',
145
212
  version: '1.0.0'
146
213
  });
147
- registerTools(server, apiClient);
148
- transport = new StdioServerTransport();
214
+ if (mode === 'public') {
215
+ registerPublicTools(server, apiClient);
216
+ } else {
217
+ registerTools(server, apiClient);
218
+ }
219
+ transport = (_options_transport = options.transport) !== null && _options_transport !== void 0 ? _options_transport : new StdioServerTransport();
220
+ // The MCP SDK's connect() accepts any transport implementing the shared
221
+ // interface; tests pass an InMemoryTransport and production passes the
222
+ // stdio transport. Typing is loose here to avoid re-exporting the
223
+ // transport interface type from the SDK just for this seam.
149
224
  return [
150
225
  4,
151
226
  server.connect(transport)
@@ -153,13 +228,123 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
153
228
  case 1:
154
229
  _state.sent();
155
230
  return [
156
- 2
231
+ 2,
232
+ {
233
+ server: server
234
+ }
157
235
  ];
158
236
  }
159
237
  });
160
- })();
238
+ }).apply(this, arguments);
161
239
  }
162
- function registerTools(server, api) {
240
+ export function registerPublicTools(server, api) {
241
+ server.tool('publish', 'Publish an anonymous HTML or Markdown artifact. Returns a preview URL (anyone can view) and a one-shot claim URL the user visits to move it into their display.dev organization.', {
242
+ content: z.string().optional().describe('HTML or Markdown content to publish'),
243
+ file_path: z.string().optional().describe('Path to a local file to publish'),
244
+ name: z.string().optional().describe('Optional display name (defaults to filename stem)'),
245
+ format: z.enum([
246
+ 'html',
247
+ 'md'
248
+ ]).default('html').describe('Content format')
249
+ }, function(args) {
250
+ return _async_to_generator(function() {
251
+ var hasContent, hasFilePath, content, _tmp, result, err;
252
+ return _ts_generator(this, function(_state) {
253
+ switch(_state.label){
254
+ case 0:
255
+ hasContent = args.content !== undefined;
256
+ hasFilePath = args.file_path !== undefined;
257
+ if (hasContent && hasFilePath) {
258
+ return [
259
+ 2,
260
+ {
261
+ content: [
262
+ {
263
+ type: 'text',
264
+ text: JSON.stringify({
265
+ error: 'ambiguous_input',
266
+ message: 'Provide either content or file_path, not both'
267
+ })
268
+ }
269
+ ],
270
+ isError: true
271
+ }
272
+ ];
273
+ }
274
+ if (!hasContent && !hasFilePath) {
275
+ return [
276
+ 2,
277
+ {
278
+ content: [
279
+ {
280
+ type: 'text',
281
+ text: JSON.stringify({
282
+ error: 'missing_content',
283
+ message: 'Either content or file_path is required'
284
+ })
285
+ }
286
+ ],
287
+ isError: true
288
+ }
289
+ ];
290
+ }
291
+ _state.label = 1;
292
+ case 1:
293
+ _state.trys.push([
294
+ 1,
295
+ 6,
296
+ ,
297
+ 7
298
+ ]);
299
+ if (!hasFilePath) return [
300
+ 3,
301
+ 3
302
+ ];
303
+ return [
304
+ 4,
305
+ readFile(resolve(args.file_path), 'utf-8')
306
+ ];
307
+ case 2:
308
+ _tmp = _state.sent();
309
+ return [
310
+ 3,
311
+ 4
312
+ ];
313
+ case 3:
314
+ _tmp = args.content;
315
+ _state.label = 4;
316
+ case 4:
317
+ content = _tmp;
318
+ return [
319
+ 4,
320
+ api.publishPublic({
321
+ content: content,
322
+ name: args.name,
323
+ format: args.format
324
+ })
325
+ ];
326
+ case 5:
327
+ result = _state.sent();
328
+ return [
329
+ 2,
330
+ okResponse(result)
331
+ ];
332
+ case 6:
333
+ err = _state.sent();
334
+ return [
335
+ 2,
336
+ errorResponse(err)
337
+ ];
338
+ case 7:
339
+ return [
340
+ 2
341
+ ];
342
+ }
343
+ });
344
+ })();
345
+ });
346
+ }
347
+ export function registerTools(server, api) {
163
348
  server.tool('publish', 'Publish an HTML or Markdown artifact behind company auth', {
164
349
  content: z.string().optional().describe('HTML or Markdown content to publish'),
165
350
  file_path: z.string().optional().describe('Path to a local file to publish'),
@@ -175,10 +360,15 @@ function registerTools(server, api) {
175
360
  visibility: z.enum([
176
361
  'public',
177
362
  'company'
178
- ]).optional().describe('Artifact visibility. Omit to keep current on update; defaults to "company" on create.')
363
+ ]).optional().describe('Artifact visibility. Omit to keep current on update; defaults to "company" on create.'),
364
+ show_branding: z.enum([
365
+ 'show',
366
+ 'hide',
367
+ 'inherit'
368
+ ]).optional().describe('display.dev attribution bar override. Paid tier only; defaults to org setting when omitted.')
179
369
  }, function(args) {
180
370
  return _async_to_generator(function() {
181
- var _args_name, content, hasContent, hasFilePath, absPath, result, _args_name1;
371
+ var _args_name, hasContent, hasFilePath, _args_name1, content, _tmp, result, _tmp1, err;
182
372
  return _ts_generator(this, function(_state) {
183
373
  switch(_state.label){
184
374
  case 0:
@@ -252,25 +442,7 @@ function registerTools(server, api) {
252
442
  }
253
443
  ];
254
444
  }
255
- if (!hasFilePath) return [
256
- 3,
257
- 2
258
- ];
259
- absPath = resolve(args.file_path);
260
- return [
261
- 4,
262
- readFile(absPath, 'utf-8')
263
- ];
264
- case 1:
265
- content = _state.sent();
266
- return [
267
- 3,
268
- 3
269
- ];
270
- case 2:
271
- if (hasContent) {
272
- content = args.content;
273
- } else {
445
+ if (!hasContent && !hasFilePath) {
274
446
  return [
275
447
  2,
276
448
  {
@@ -287,11 +459,36 @@ function registerTools(server, api) {
287
459
  }
288
460
  ];
289
461
  }
290
- _state.label = 3;
462
+ _state.label = 1;
463
+ case 1:
464
+ _state.trys.push([
465
+ 1,
466
+ 9,
467
+ ,
468
+ 10
469
+ ]);
470
+ if (!hasFilePath) return [
471
+ 3,
472
+ 3
473
+ ];
474
+ return [
475
+ 4,
476
+ readFile(resolve(args.file_path), 'utf-8')
477
+ ];
478
+ case 2:
479
+ _tmp = _state.sent();
480
+ return [
481
+ 3,
482
+ 4
483
+ ];
291
484
  case 3:
485
+ _tmp = args.content;
486
+ _state.label = 4;
487
+ case 4:
488
+ content = _tmp;
292
489
  if (!args.short_id) return [
293
490
  3,
294
- 5
491
+ 6
295
492
  ];
296
493
  return [
297
494
  4,
@@ -302,16 +499,17 @@ function registerTools(server, api) {
302
499
  theme: args.theme,
303
500
  share: args.share,
304
501
  clearShares: args.clear_shares,
305
- visibility: args.visibility
502
+ visibility: args.visibility,
503
+ showBranding: args.show_branding
306
504
  })
307
505
  ];
308
- case 4:
309
- result = _state.sent();
506
+ case 5:
507
+ _tmp1 = _state.sent();
310
508
  return [
311
509
  3,
312
- 7
510
+ 8
313
511
  ];
314
- case 5:
512
+ case 6:
315
513
  return [
316
514
  4,
317
515
  api.publish({
@@ -320,23 +518,28 @@ function registerTools(server, api) {
320
518
  format: args.format,
321
519
  theme: args.theme,
322
520
  share: args.share,
323
- visibility: args.visibility
521
+ visibility: args.visibility,
522
+ showBranding: args.show_branding
324
523
  })
325
524
  ];
326
- case 6:
327
- result = _state.sent();
328
- _state.label = 7;
329
525
  case 7:
526
+ _tmp1 = _state.sent();
527
+ _state.label = 8;
528
+ case 8:
529
+ result = _tmp1;
330
530
  return [
331
531
  2,
332
- {
333
- content: [
334
- {
335
- type: 'text',
336
- text: JSON.stringify(result)
337
- }
338
- ]
339
- }
532
+ okResponse(result)
533
+ ];
534
+ case 9:
535
+ err = _state.sent();
536
+ return [
537
+ 2,
538
+ errorResponse(err)
539
+ ];
540
+ case 10:
541
+ return [
542
+ 2
340
543
  ];
341
544
  }
342
545
  });
@@ -359,10 +562,16 @@ function registerTools(server, api) {
359
562
  limit: z.number().optional().describe('Max results to return (1-100)')
360
563
  }, function(args) {
361
564
  return _async_to_generator(function() {
362
- var results;
565
+ var results, err;
363
566
  return _ts_generator(this, function(_state) {
364
567
  switch(_state.label){
365
568
  case 0:
569
+ _state.trys.push([
570
+ 0,
571
+ 2,
572
+ ,
573
+ 3
574
+ ]);
366
575
  return [
367
576
  4,
368
577
  api.find(args)
@@ -371,14 +580,17 @@ function registerTools(server, api) {
371
580
  results = _state.sent();
372
581
  return [
373
582
  2,
374
- {
375
- content: [
376
- {
377
- type: 'text',
378
- text: JSON.stringify(results)
379
- }
380
- ]
381
- }
583
+ okResponse(results)
584
+ ];
585
+ case 2:
586
+ err = _state.sent();
587
+ return [
588
+ 2,
589
+ errorResponse(err)
590
+ ];
591
+ case 3:
592
+ return [
593
+ 2
382
594
  ];
383
595
  }
384
596
  });
@@ -389,10 +601,16 @@ function registerTools(server, api) {
389
601
  include: z.array(z.string()).optional().describe('Include additional data (e.g. "versions")')
390
602
  }, function(args) {
391
603
  return _async_to_generator(function() {
392
- var result;
604
+ var result, err;
393
605
  return _ts_generator(this, function(_state) {
394
606
  switch(_state.label){
395
607
  case 0:
608
+ _state.trys.push([
609
+ 0,
610
+ 2,
611
+ ,
612
+ 3
613
+ ]);
396
614
  return [
397
615
  4,
398
616
  api.get(args.short_id, args.include)
@@ -401,14 +619,17 @@ function registerTools(server, api) {
401
619
  result = _state.sent();
402
620
  return [
403
621
  2,
404
- {
405
- content: [
406
- {
407
- type: 'text',
408
- text: JSON.stringify(result)
409
- }
410
- ]
411
- }
622
+ okResponse(result)
623
+ ];
624
+ case 2:
625
+ err = _state.sent();
626
+ return [
627
+ 2,
628
+ errorResponse(err)
629
+ ];
630
+ case 3:
631
+ return [
632
+ 2
412
633
  ];
413
634
  }
414
635
  });
@@ -419,7 +640,7 @@ function registerTools(server, api) {
419
640
  confirm: z.boolean().describe('Must be true to confirm deletion')
420
641
  }, function(args) {
421
642
  return _async_to_generator(function() {
422
- var result;
643
+ var result, err;
423
644
  return _ts_generator(this, function(_state) {
424
645
  switch(_state.label){
425
646
  case 0:
@@ -440,22 +661,121 @@ function registerTools(server, api) {
440
661
  }
441
662
  ];
442
663
  }
664
+ _state.label = 1;
665
+ case 1:
666
+ _state.trys.push([
667
+ 1,
668
+ 3,
669
+ ,
670
+ 4
671
+ ]);
443
672
  return [
444
673
  4,
445
674
  api.delete(args.short_id)
446
675
  ];
676
+ case 2:
677
+ result = _state.sent();
678
+ return [
679
+ 2,
680
+ okResponse(result)
681
+ ];
682
+ case 3:
683
+ err = _state.sent();
684
+ return [
685
+ 2,
686
+ errorResponse(err)
687
+ ];
688
+ case 4:
689
+ return [
690
+ 2
691
+ ];
692
+ }
693
+ });
694
+ })();
695
+ });
696
+ // Agent-native parity for the artifact-detail per-artifact toggle.
697
+ // Metadata-only: does NOT bump the artifact version. Use the `publish`
698
+ // tool (with `show_branding`) when you're changing content at the same
699
+ // time so both writes happen in one transaction.
700
+ server.tool('artifact_set_branding', 'Override display.dev branding for an existing artifact without re-publishing. Paid tiers only (free-tier orgs must keep inherit).', {
701
+ short_id: z.string().describe('Artifact shortId'),
702
+ show_branding: z.enum([
703
+ 'show',
704
+ 'hide',
705
+ 'inherit'
706
+ ]).describe('show = force branding on; hide = force off; inherit = follow org default')
707
+ }, function(args) {
708
+ return _async_to_generator(function() {
709
+ var result, err;
710
+ return _ts_generator(this, function(_state) {
711
+ switch(_state.label){
712
+ case 0:
713
+ _state.trys.push([
714
+ 0,
715
+ 2,
716
+ ,
717
+ 3
718
+ ]);
719
+ return [
720
+ 4,
721
+ api.setArtifactBranding(args.short_id, args.show_branding)
722
+ ];
723
+ case 1:
724
+ result = _state.sent();
725
+ return [
726
+ 2,
727
+ okResponse(result)
728
+ ];
729
+ case 2:
730
+ err = _state.sent();
731
+ return [
732
+ 2,
733
+ errorResponse(err)
734
+ ];
735
+ case 3:
736
+ return [
737
+ 2
738
+ ];
739
+ }
740
+ });
741
+ })();
742
+ });
743
+ // Agent-native parity for the Settings → Branding dashboard toggle.
744
+ // Pairs with `publish`'s `show_branding` param: this tool controls the
745
+ // default; that param overrides it per-artifact.
746
+ server.tool('org_set_branding', 'Enable or disable display.dev branding for every artifact in the org (paid tiers only). Per-artifact overrides keep precedence.', {
747
+ enabled: z.boolean().describe('true to show the bar by default; false to hide it')
748
+ }, function(args) {
749
+ return _async_to_generator(function() {
750
+ var result, err;
751
+ return _ts_generator(this, function(_state) {
752
+ switch(_state.label){
753
+ case 0:
754
+ _state.trys.push([
755
+ 0,
756
+ 2,
757
+ ,
758
+ 3
759
+ ]);
760
+ return [
761
+ 4,
762
+ api.setOrgBranding(args.enabled)
763
+ ];
447
764
  case 1:
448
765
  result = _state.sent();
449
766
  return [
450
767
  2,
451
- {
452
- content: [
453
- {
454
- type: 'text',
455
- text: JSON.stringify(result)
456
- }
457
- ]
458
- }
768
+ okResponse(result)
769
+ ];
770
+ case 2:
771
+ err = _state.sent();
772
+ return [
773
+ 2,
774
+ errorResponse(err)
775
+ ];
776
+ case 3:
777
+ return [
778
+ 2
459
779
  ];
460
780
  }
461
781
  });
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@displaydev/cli",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "dsp": "dist/main.js"
7
7
  },
8
8
  "files": [
9
9
  "dist",
10
- "!dist/*.spec.js"
10
+ "!dist/*.spec.js",
11
+ "!dist/test-helpers.js"
11
12
  ],
12
13
  "scripts": {
13
14
  "build": "swc src -d dist --strip-leading-paths",