@displaydev/cli 0.17.0 → 0.18.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.
@@ -549,44 +549,76 @@ export var ApiClient = /*#__PURE__*/ function() {
549
549
  key: "find",
550
550
  value: function find(params) {
551
551
  return _async_to_generator(function() {
552
- var searchParams, qs, res;
552
+ var searchParams, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, a, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, v, qs;
553
553
  return _ts_generator(this, function(_state) {
554
- switch(_state.label){
555
- case 0:
556
- searchParams = new URLSearchParams();
557
- if (params.query) {
558
- searchParams.set('q', params.query);
559
- }
560
- if (params.mine) {
561
- searchParams.append('author', 'me');
562
- }
563
- if (params.publishedBy) {
564
- searchParams.set('publishedBy', params.publishedBy);
565
- }
566
- if (params.since) {
567
- searchParams.set('since', params.since);
554
+ searchParams = new URLSearchParams();
555
+ if (params.query) {
556
+ searchParams.set('q', params.query);
557
+ }
558
+ if (params.author) {
559
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
560
+ try {
561
+ for(_iterator = params.author[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
562
+ a = _step.value;
563
+ searchParams.append('author', a);
568
564
  }
569
- if (params.sort) {
570
- searchParams.set('sort', params.sort);
565
+ } catch (err) {
566
+ _didIteratorError = true;
567
+ _iteratorError = err;
568
+ } finally{
569
+ try {
570
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
571
+ _iterator.return();
572
+ }
573
+ } finally{
574
+ if (_didIteratorError) {
575
+ throw _iteratorError;
576
+ }
571
577
  }
572
- if (params.dir) {
573
- searchParams.set('dir', params.dir);
578
+ }
579
+ }
580
+ if (params.visibility) {
581
+ _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
582
+ try {
583
+ for(_iterator1 = params.visibility[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
584
+ v = _step1.value;
585
+ searchParams.append('visibility', v);
574
586
  }
575
- if (params.limit) {
576
- searchParams.set('limit', String(params.limit));
587
+ } catch (err) {
588
+ _didIteratorError1 = true;
589
+ _iteratorError1 = err;
590
+ } finally{
591
+ try {
592
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
593
+ _iterator1.return();
594
+ }
595
+ } finally{
596
+ if (_didIteratorError1) {
597
+ throw _iteratorError1;
598
+ }
577
599
  }
578
- qs = searchParams.toString();
579
- return [
580
- 4,
581
- this.request('GET', "/v1/artifacts".concat(qs ? "?".concat(qs) : ''))
582
- ];
583
- case 1:
584
- res = _state.sent();
585
- return [
586
- 2,
587
- res.data
588
- ];
600
+ }
601
+ }
602
+ if (params.since) {
603
+ searchParams.set('since', params.since);
589
604
  }
605
+ if (params.sort) {
606
+ searchParams.set('sort', params.sort);
607
+ }
608
+ if (params.dir) {
609
+ searchParams.set('dir', params.dir);
610
+ }
611
+ if (params.cursor) {
612
+ searchParams.set('cursor', params.cursor);
613
+ }
614
+ if (params.limit !== undefined) {
615
+ searchParams.set('limit', String(params.limit));
616
+ }
617
+ qs = searchParams.toString();
618
+ return [
619
+ 2,
620
+ this.request('GET', "/v1/artifacts".concat(qs ? "?".concat(qs) : ''))
621
+ ];
590
622
  });
591
623
  }).call(this);
592
624
  }
@@ -287,6 +287,17 @@ function _ts_generator(thisArg, body) {
287
287
  }
288
288
  import { extname } from 'node:path';
289
289
  export var DEFAULT_API_URL = 'https://api.display.dev';
290
+ export function classifyApiKey(apiKey) {
291
+ // BA mints keys with no separator after the prefix — `sk_live<body>`,
292
+ // not `sk_live_<body>`. Mirrors the live check at api/src/guards/auth.guard.ts.
293
+ if (apiKey.startsWith('sk_live')) {
294
+ return 'user';
295
+ }
296
+ if (apiKey.startsWith('org_live')) {
297
+ return 'org';
298
+ }
299
+ return 'session';
300
+ }
290
301
  export var InvalidFlagError = /*#__PURE__*/ function(Error1) {
291
302
  "use strict";
292
303
  _inherits(InvalidFlagError, Error1);
@@ -399,7 +410,8 @@ export function resolveAuth(env, config) {
399
410
  var apiUrl = (_ref = (_env_DISPLAYDEV_API_URL = env.DISPLAYDEV_API_URL) !== null && _env_DISPLAYDEV_API_URL !== void 0 ? _env_DISPLAYDEV_API_URL : config === null || config === void 0 ? void 0 : config.apiUrl) !== null && _ref !== void 0 ? _ref : DEFAULT_API_URL;
400
411
  return {
401
412
  apiKey: apiKey,
402
- apiUrl: apiUrl
413
+ apiUrl: apiUrl,
414
+ keyType: classifyApiKey(apiKey)
403
415
  };
404
416
  }
405
417
  export function classifyBrandingError(message) {
package/dist/main.js CHANGED
@@ -726,11 +726,24 @@ program.command('rename <shortId>').description('Rename a published artifact. Sl
726
726
  })();
727
727
  });
728
728
  // --- find ---
729
- 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) {
729
+ function collectAuthor(value, prev) {
730
+ return prev.concat(value);
731
+ }
732
+ function parseVisibilityCsv(raw) {
733
+ return raw.split(',').map(function(v) {
734
+ return v.trim();
735
+ }).filter(Boolean);
736
+ }
737
+ var VISIBILITY_VALUES = new Set([
738
+ 'public',
739
+ 'company',
740
+ 'private'
741
+ ]);
742
+ program.command('find [query]').alias('list').description('List or search artifacts. Omit [query] to list every artifact (paginated).').option('--author <a>', 'Filter by author (repeatable). Each value: email, userId, or "me".', collectAuthor, []).option('--visibility <list>', 'CSV of visibility levels: public, company, private. "private" returns only your own.').option('--since <date>', 'Filter by updated since ISO date').option('--sort <col>', 'Sort column: updated_at, view_count, name').option('--dir <direction>', 'Sort direction: asc or desc').option('--cursor <token>', 'Opaque pagination token from a prior response. Drop the cursor when filters change — the wire only validates it against sort/dir, so reusing it after changing --author / --visibility / --since / [query] silently skews results.').option('--limit <n>', 'Max rows to fetch (1-100)', function(v) {
730
743
  return parseInt(v, 10);
731
744
  }).action(function(query, opts) {
732
745
  return _async_to_generator(function() {
733
- var auth, client, results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, a;
746
+ var visibility, tokens, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, v, auth, client, response, err, msg, data, nextCursor, totalCount, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, a;
734
747
  return _ts_generator(this, function(_state) {
735
748
  switch(_state.label){
736
749
  case 0:
@@ -746,53 +759,126 @@ program.command('find [query]').description('Search for artifacts').option('--by
746
759
  console.error("Invalid --dir: ".concat(opts.dir, ". Use asc or desc."));
747
760
  process.exit(1);
748
761
  }
762
+ if (opts.visibility) {
763
+ tokens = parseVisibilityCsv(opts.visibility);
764
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
765
+ try {
766
+ for(_iterator = tokens[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
767
+ v = _step.value;
768
+ if (!VISIBILITY_VALUES.has(v)) {
769
+ console.error("Invalid --visibility: ".concat(v, ". Use public, company, or private."));
770
+ process.exit(1);
771
+ }
772
+ }
773
+ } catch (err) {
774
+ _didIteratorError = true;
775
+ _iteratorError = err;
776
+ } finally{
777
+ try {
778
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
779
+ _iterator.return();
780
+ }
781
+ } finally{
782
+ if (_didIteratorError) {
783
+ throw _iteratorError;
784
+ }
785
+ }
786
+ }
787
+ visibility = tokens;
788
+ }
749
789
  return [
750
790
  4,
751
791
  resolveAuthOrConfig()
752
792
  ];
753
793
  case 1:
754
794
  auth = _state.sent();
795
+ // The wire silently drops `me` when authenticated with an org API key (no
796
+ // session user → caller id is null in resolveAuthorIds). Catch that at the
797
+ // command layer so the user gets an explicit failure rather than an
798
+ // unfiltered list. Trim each value to mirror the wire — it trims tokens
799
+ // before resolving `me`, so `--author ' me '` would otherwise bypass the
800
+ // guard and re-introduce the silent-broaden bug.
801
+ if (auth.keyType === 'org' && opts.author.some(function(a) {
802
+ return a.trim() === 'me';
803
+ })) {
804
+ console.error('--author me requires a user-scoped credential. Use a user API key or sign in via dashboard.');
805
+ process.exit(1);
806
+ }
755
807
  client = createClient(auth);
808
+ _state.label = 2;
809
+ case 2:
810
+ _state.trys.push([
811
+ 2,
812
+ 4,
813
+ ,
814
+ 5
815
+ ]);
756
816
  return [
757
817
  4,
758
818
  client.find({
759
819
  query: query,
760
- publishedBy: opts.by,
761
- mine: opts.mine,
820
+ author: opts.author.length > 0 ? opts.author : undefined,
821
+ visibility: visibility,
762
822
  since: opts.since,
763
823
  sort: opts.sort,
764
824
  dir: opts.dir,
825
+ cursor: opts.cursor,
765
826
  limit: opts.limit
766
827
  })
767
828
  ];
768
- case 2:
769
- results = _state.sent();
770
- if (results.length === 0) {
829
+ case 3:
830
+ response = _state.sent();
831
+ return [
832
+ 3,
833
+ 5
834
+ ];
835
+ case 4:
836
+ err = _state.sent();
837
+ msg = _instanceof(err, Error) ? err.message : String(err);
838
+ console.error(msg);
839
+ process.exit(1);
840
+ return [
841
+ 3,
842
+ 5
843
+ ];
844
+ case 5:
845
+ data = response.data, nextCursor = response.nextCursor, totalCount = response.totalCount;
846
+ if (data.length === 0) {
771
847
  console.log('No artifacts found.');
772
848
  return [
773
849
  2
774
850
  ];
775
851
  }
776
- _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
852
+ _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
777
853
  try {
778
- for(_iterator = results[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
779
- a = _step.value;
854
+ for(_iterator1 = data[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
855
+ a = _step1.value;
780
856
  console.log("".concat(a.shortId, " v").concat(a.currentVersion, " ").concat(a.name, " ").concat(a.url));
781
857
  }
782
858
  } catch (err) {
783
- _didIteratorError = true;
784
- _iteratorError = err;
859
+ _didIteratorError1 = true;
860
+ _iteratorError1 = err;
785
861
  } finally{
786
862
  try {
787
- if (!_iteratorNormalCompletion && _iterator.return != null) {
788
- _iterator.return();
863
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
864
+ _iterator1.return();
789
865
  }
790
866
  } finally{
791
- if (_didIteratorError) {
792
- throw _iteratorError;
867
+ if (_didIteratorError1) {
868
+ throw _iteratorError1;
793
869
  }
794
870
  }
795
871
  }
872
+ // Footer on stderr so pipe consumers (`dsp find | xargs ...`) get clean
873
+ // stdout. Order: count line first, then the next-page hint.
874
+ if (totalCount === -1) {
875
+ process.stderr.write("Showing ".concat(data.length, " matching artifacts (count exceeded the budget; rerun with a tighter filter to get an exact total).\n"));
876
+ } else if (totalCount >= 0) {
877
+ process.stderr.write("Showing ".concat(data.length, "/").concat(totalCount, " matching artifacts.\n"));
878
+ }
879
+ if (nextCursor !== null) {
880
+ process.stderr.write("More results available. Re-run with --cursor ".concat(nextCursor, " to fetch the next page.\n"));
881
+ }
796
882
  return [
797
883
  2
798
884
  ];
@@ -27,19 +27,6 @@ function _async_to_generator(fn) {
27
27
  });
28
28
  };
29
29
  }
30
- function _define_property(obj, key, value) {
31
- if (key in obj) {
32
- Object.defineProperty(obj, key, {
33
- value: value,
34
- enumerable: true,
35
- configurable: true,
36
- writable: true
37
- });
38
- } else {
39
- obj[key] = value;
40
- }
41
- return obj;
42
- }
43
30
  function _instanceof(left, right) {
44
31
  "@swc/helpers - instanceof";
45
32
  if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
@@ -48,57 +35,6 @@ function _instanceof(left, right) {
48
35
  return left instanceof right;
49
36
  }
50
37
  }
51
- function _object_spread(target) {
52
- for(var i = 1; i < arguments.length; i++){
53
- var source = arguments[i] != null ? arguments[i] : {};
54
- var ownKeys = Object.keys(source);
55
- if (typeof Object.getOwnPropertySymbols === "function") {
56
- ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
57
- return Object.getOwnPropertyDescriptor(source, sym).enumerable;
58
- }));
59
- }
60
- ownKeys.forEach(function(key) {
61
- _define_property(target, key, source[key]);
62
- });
63
- }
64
- return target;
65
- }
66
- function _object_without_properties(source, excluded) {
67
- if (source == null) return {};
68
- var target = {}, sourceKeys, key, i;
69
- if (typeof Reflect !== "undefined" && Reflect.ownKeys) {
70
- sourceKeys = Reflect.ownKeys(Object(source));
71
- for(i = 0; i < sourceKeys.length; i++){
72
- key = sourceKeys[i];
73
- if (excluded.indexOf(key) >= 0) continue;
74
- if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
75
- target[key] = source[key];
76
- }
77
- return target;
78
- }
79
- target = _object_without_properties_loose(source, excluded);
80
- if (Object.getOwnPropertySymbols) {
81
- sourceKeys = Object.getOwnPropertySymbols(source);
82
- for(i = 0; i < sourceKeys.length; i++){
83
- key = sourceKeys[i];
84
- if (excluded.indexOf(key) >= 0) continue;
85
- if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
86
- target[key] = source[key];
87
- }
88
- }
89
- return target;
90
- }
91
- function _object_without_properties_loose(source, excluded) {
92
- if (source == null) return {};
93
- var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
94
- for(i = 0; i < sourceKeys.length; i++){
95
- key = sourceKeys[i];
96
- if (excluded.indexOf(key) >= 0) continue;
97
- if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
98
- target[key] = source[key];
99
- }
100
- return target;
101
- }
102
38
  function _ts_generator(thisArg, body) {
103
39
  var f, y, t, _ = {
104
40
  label: 0,
@@ -624,24 +560,29 @@ export function registerTools(server, api) {
624
560
  });
625
561
  })();
626
562
  });
627
- server.tool('find', 'Search for artifacts in the organization', {
628
- query: z.string().optional().describe('Search by artifact name'),
629
- published_by: z.string().optional().describe('Filter by publisher email'),
630
- mine: z.boolean().optional().describe('Limit results to your own artifacts'),
631
- since: z.string().optional().describe('Filter by updated since ISO date'),
563
+ server.tool('find', 'List or search artifacts in the caller\'s organization. Omit `query` to list every artifact (paginated). Filter by name, one-or-more authors, one-or-more visibilities, or update time. Sort by `updated_at` (default), `view_count`, or `name`. Paginate via `cursor` — if the result includes a non-null `nextCursor`, pass it back to fetch the next page; if filters change between calls, drop the cursor. The response also carries `totalCount` (`-1` means the count query exceeded its budget — treat as "many"). `visibility: ["private"]` returns only your own private artifacts, not org-wide.', {
564
+ query: z.string().optional().describe('Search by artifact name (case-insensitive substring). Omit to list all artifacts.'),
565
+ author: z.array(z.string()).optional().describe('Filter by one or more authors. Each value: email, userId, or the literal "me". Multiple values are ORed. "me" requires a user-scoped credential — with an org API key the wire drops it.'),
566
+ visibility: z.array(z.enum([
567
+ 'public',
568
+ 'company',
569
+ 'private'
570
+ ])).optional().describe('Filter by one or more visibility levels. NOTE: "private" is creator-scoped — only your own private artifacts are returned, not org-wide.'),
571
+ since: z.string().optional().describe('ISO timestamp; only artifacts updated on or after this point.'),
632
572
  sort: z.enum([
633
573
  'updated_at',
634
574
  'view_count',
635
575
  'name'
636
- ]).optional().describe('Sort column'),
576
+ ]).optional().describe('Sort column. Defaults to updated_at.'),
637
577
  dir: z.enum([
638
578
  'asc',
639
579
  'desc'
640
- ]).optional().describe('Sort direction'),
641
- limit: z.number().optional().describe('Max results to return (1-100)')
580
+ ]).optional().describe('Sort direction. Defaults: desc for updated_at and view_count, asc for name.'),
581
+ cursor: z.string().optional().describe('Opaque pagination token from a prior response. Pass it back to fetch the next page. WARNING: only valid for the same `sort`/`dir`/filter set that issued it — change a filter and drop the cursor, or results will be skewed without an error.'),
582
+ limit: z.number().int().min(1).max(100).optional().describe('Max results per page (1–100, default 50).')
642
583
  }, function(args) {
643
584
  return _async_to_generator(function() {
644
- var publishedBy, rest, results, err;
585
+ var result, err;
645
586
  return _ts_generator(this, function(_state) {
646
587
  switch(_state.label){
647
588
  case 0:
@@ -651,25 +592,15 @@ export function registerTools(server, api) {
651
592
  ,
652
593
  3
653
594
  ]);
654
- // Translate the snake_case MCP arg to the camelCase wire shape that
655
- // ApiClient.find() forwards to GET /v1/artifacts. MCP convention
656
- // prefers snake_case in tool schemas; the wire is camelCase
657
- // (api-conventions §1.2). Without this map, `published_by` was
658
- // silently dropped on the floor and the filter went unfiltered.
659
- publishedBy = args.published_by, rest = _object_without_properties(args, [
660
- "published_by"
661
- ]);
662
595
  return [
663
596
  4,
664
- api.find(_object_spread({}, rest, publishedBy !== undefined ? {
665
- publishedBy: publishedBy
666
- } : {}))
597
+ api.find(args)
667
598
  ];
668
599
  case 1:
669
- results = _state.sent();
600
+ result = _state.sent();
670
601
  return [
671
602
  2,
672
- okResponse(results)
603
+ okResponse(result)
673
604
  ];
674
605
  case 2:
675
606
  err = _state.sent();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@displaydev/cli",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "dsp": "dist/main.js"