@dereekb/dbx-cli 13.13.0 → 13.15.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.
@@ -57,6 +57,11 @@ var SUPPORTED_VERBS = new Set([
57
57
  'query',
58
58
  'invoke'
59
59
  ]);
60
+ /**
61
+ * JSDoc tag (without leading `@`) on a CRUD leaf naming the interface that a handler's
62
+ * `mapSuccessfulResult` produces for MCP. When present, the MCP manifest output schema is
63
+ * synthesized from this type instead of the raw result type.
64
+ */ var DBX_MODEL_API_MCP_RESULT_MARKER = 'dbxModelApiMcpResult';
60
65
  /**
61
66
  * Walks a `<model>.api.ts` source and returns one {@link CrudEntry} per
62
67
  * callable leaf (CRUD or standalone). Best-effort: malformed configs return
@@ -136,6 +141,7 @@ function extractCrudEntries(source) {
136
141
  valueNode: verbValueNode,
137
142
  entries: entries,
138
143
  fallbackDescription: readJsDocSummary(verbMember),
144
+ fallbackMcpResultTypeName: readJsDocTagValue(verbMember, DBX_MODEL_API_MCP_RESULT_MARKER),
139
145
  resolveTypeDocs: resolveTypeDocs
140
146
  });
141
147
  }
@@ -187,6 +193,8 @@ function extractCrudEntries(source) {
187
193
  var tuple = valueNode1 ? readTupleParamsResult(valueNode1) : undefined;
188
194
  var paramsDocs = resolveTypeDocs(tuple === null || tuple === void 0 ? void 0 : tuple.params);
189
195
  var resultDocs = resolveTypeDocs(tuple === null || tuple === void 0 ? void 0 : tuple.result);
196
+ var mcpResultTypeName = readJsDocTagValue(member1, DBX_MODEL_API_MCP_RESULT_MARKER);
197
+ var mcpResultDocs = resolveTypeDocs(mcpResultTypeName);
190
198
  entries.push({
191
199
  model: key,
192
200
  verb: 'standalone',
@@ -199,7 +207,10 @@ function extractCrudEntries(source) {
199
207
  paramsFields: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.fields,
200
208
  paramsHasApiParamsTag: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.hasApiParamsTag,
201
209
  resultTypeDescription: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.typeDescription,
202
- resultFields: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.fields
210
+ resultFields: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.fields,
211
+ mcpResultTypeName: mcpResultTypeName,
212
+ mcpResultTypeDescription: mcpResultDocs === null || mcpResultDocs === void 0 ? void 0 : mcpResultDocs.typeDescription,
213
+ mcpResultFields: mcpResultDocs === null || mcpResultDocs === void 0 ? void 0 : mcpResultDocs.fields
203
214
  });
204
215
  }
205
216
  } catch (err) {
@@ -355,7 +366,7 @@ function isNullLiteralType(node) {
355
366
  }
356
367
  function collectVerbEntries(input) {
357
368
  var _readTupleParamsResult;
358
- var modelName = input.modelName, verb = input.verb, valueNode = input.valueNode, entries = input.entries, fallbackDescription = input.fallbackDescription, resolveTypeDocs = input.resolveTypeDocs;
369
+ var modelName = input.modelName, verb = input.verb, valueNode = input.valueNode, entries = input.entries, fallbackDescription = input.fallbackDescription, fallbackMcpResultTypeName = input.fallbackMcpResultTypeName, resolveTypeDocs = input.resolveTypeDocs;
359
370
  if (tsMorph.Node.isTypeLiteral(valueNode)) {
360
371
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
361
372
  try {
@@ -370,6 +381,8 @@ function collectVerbEntries(input) {
370
381
  var leaf = leafNode ? (_readTupleParamsResult1 = readTupleParamsResult(leafNode)) !== null && _readTupleParamsResult1 !== void 0 ? _readTupleParamsResult1 : readBareParams(leafNode) : undefined;
371
382
  var paramsDocs = resolveTypeDocs(leaf === null || leaf === void 0 ? void 0 : leaf.params);
372
383
  var resultDocs = resolveTypeDocs(leaf === null || leaf === void 0 ? void 0 : leaf.result);
384
+ var mcpResultTypeName = readJsDocTagValue(specMember, DBX_MODEL_API_MCP_RESULT_MARKER);
385
+ var mcpResultDocs = resolveTypeDocs(mcpResultTypeName);
373
386
  entries.push({
374
387
  model: modelName,
375
388
  verb: verb,
@@ -382,7 +395,10 @@ function collectVerbEntries(input) {
382
395
  paramsFields: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.fields,
383
396
  paramsHasApiParamsTag: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.hasApiParamsTag,
384
397
  resultTypeDescription: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.typeDescription,
385
- resultFields: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.fields
398
+ resultFields: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.fields,
399
+ mcpResultTypeName: mcpResultTypeName,
400
+ mcpResultTypeDescription: mcpResultDocs === null || mcpResultDocs === void 0 ? void 0 : mcpResultDocs.typeDescription,
401
+ mcpResultFields: mcpResultDocs === null || mcpResultDocs === void 0 ? void 0 : mcpResultDocs.fields
386
402
  });
387
403
  }
388
404
  } catch (err) {
@@ -404,6 +420,7 @@ function collectVerbEntries(input) {
404
420
  var leaf1 = (_readTupleParamsResult = readTupleParamsResult(valueNode)) !== null && _readTupleParamsResult !== void 0 ? _readTupleParamsResult : readBareParams(valueNode);
405
421
  var paramsDocs1 = resolveTypeDocs(leaf1 === null || leaf1 === void 0 ? void 0 : leaf1.params);
406
422
  var resultDocs1 = resolveTypeDocs(leaf1 === null || leaf1 === void 0 ? void 0 : leaf1.result);
423
+ var mcpResultDocs1 = resolveTypeDocs(fallbackMcpResultTypeName);
407
424
  entries.push({
408
425
  model: modelName,
409
426
  verb: verb,
@@ -416,7 +433,10 @@ function collectVerbEntries(input) {
416
433
  paramsFields: paramsDocs1 === null || paramsDocs1 === void 0 ? void 0 : paramsDocs1.fields,
417
434
  paramsHasApiParamsTag: paramsDocs1 === null || paramsDocs1 === void 0 ? void 0 : paramsDocs1.hasApiParamsTag,
418
435
  resultTypeDescription: resultDocs1 === null || resultDocs1 === void 0 ? void 0 : resultDocs1.typeDescription,
419
- resultFields: resultDocs1 === null || resultDocs1 === void 0 ? void 0 : resultDocs1.fields
436
+ resultFields: resultDocs1 === null || resultDocs1 === void 0 ? void 0 : resultDocs1.fields,
437
+ mcpResultTypeName: fallbackMcpResultTypeName,
438
+ mcpResultTypeDescription: mcpResultDocs1 === null || mcpResultDocs1 === void 0 ? void 0 : mcpResultDocs1.typeDescription,
439
+ mcpResultFields: mcpResultDocs1 === null || mcpResultDocs1 === void 0 ? void 0 : mcpResultDocs1.fields
420
440
  });
421
441
  }
422
442
  function readTupleParamsResult(node) {
@@ -569,6 +589,64 @@ function readTypeDocs(sourceFile, typeName) {
569
589
  }
570
590
  return result;
571
591
  }
592
+ /**
593
+ * Reads the value token of a JSDoc tag (e.g. the `Foo` in `@dbxModelApiMcpResult Foo`).
594
+ *
595
+ * Used for value-carrying tags like `@dbxModelApiMcpResult` where the first token after the tag
596
+ * name names a type. Returns the first whitespace-delimited token of the tag's comment text.
597
+ *
598
+ * @param node - Any JSDocable ts-morph node (property signature, etc.).
599
+ * @param tagName - Tag name without the leading `@` (e.g. `'dbxModelApiMcpResult'`).
600
+ * @returns The first token of the tag's value, or `undefined` when the tag is absent or empty.
601
+ */ function readJsDocTagValue(node, tagName) {
602
+ var result;
603
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
604
+ try {
605
+ for(var _iterator = node.getJsDocs()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
606
+ var doc = _step.value;
607
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
608
+ try {
609
+ for(var _iterator1 = doc.getTags()[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
610
+ var tag = _step1.value;
611
+ if (tag.getTagName() === tagName) {
612
+ var _tag_getCommentText;
613
+ var token = (_tag_getCommentText = tag.getCommentText()) === null || _tag_getCommentText === void 0 ? void 0 : _tag_getCommentText.trim().split(/\s+/)[0];
614
+ if (token) {
615
+ result = token;
616
+ }
617
+ }
618
+ }
619
+ } catch (err) {
620
+ _didIteratorError1 = true;
621
+ _iteratorError1 = err;
622
+ } finally{
623
+ try {
624
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
625
+ _iterator1.return();
626
+ }
627
+ } finally{
628
+ if (_didIteratorError1) {
629
+ throw _iteratorError1;
630
+ }
631
+ }
632
+ }
633
+ }
634
+ } catch (err) {
635
+ _didIteratorError = true;
636
+ _iteratorError = err;
637
+ } finally{
638
+ try {
639
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
640
+ _iterator.return();
641
+ }
642
+ } finally{
643
+ if (_didIteratorError) {
644
+ throw _iteratorError;
645
+ }
646
+ }
647
+ }
648
+ return result;
649
+ }
572
650
  function readJsDocSummary(node) {
573
651
  var result;
574
652
  var docs = node.getJsDocs();
@@ -617,7 +695,9 @@ var READ_LEVEL_VALUES = new Set([
617
695
  'permissions'
618
696
  ]);
619
697
  var SERVICE_FACTORY_TAG = 'dbxModelServiceFactory';
698
+ var MCP_TOOL_NAME_SEGMENT_TAG = 'dbxModelMcpToolNameSegment';
620
699
  var MODEL_TYPE_VALUE_PATTERN = /^[a-z][A-Za-z0-9_$]*$/;
700
+ var TOOL_NAME_SEGMENT_PATTERN = /^[A-Za-z][A-Za-z0-9_$]*$/;
621
701
  /**
622
702
  * TS utility/structural wrappers that don't change the field surface for
623
703
  * inheritance walks — `Partial<T>`, `Required<T>`, `Readonly<T>`,
@@ -803,6 +883,7 @@ function buildInterface(decl) {
803
883
  var jsDocs = decl.getJsDocs();
804
884
  var hasDbxModelTag = jsDocsHaveTag(jsDocs, 'dbxModel');
805
885
  var dbxModelRead = readDbxModelReadTag(jsDocs);
886
+ var mcpToolNameSegment = readMcpToolNameSegmentTag(jsDocs);
806
887
  var extendsNames = decl.getExtends().map(resolveExtendsName);
807
888
  var props = [];
808
889
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -847,8 +928,61 @@ function buildInterface(decl) {
847
928
  props: props
848
929
  }, dbxModelRead === undefined ? {} : {
849
930
  dbxModelRead: dbxModelRead
931
+ }, mcpToolNameSegment === undefined ? {} : {
932
+ mcpToolNameSegment: mcpToolNameSegment
850
933
  });
851
934
  }
935
+ function readMcpToolNameSegmentTag(jsDocs) {
936
+ var result;
937
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
938
+ try {
939
+ for(var _iterator = jsDocs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
940
+ var doc = _step.value;
941
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
942
+ try {
943
+ for(var _iterator1 = doc.getTags()[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
944
+ var tag = _step1.value;
945
+ var _tag_getCommentText;
946
+ if (tag.getTagName() !== MCP_TOOL_NAME_SEGMENT_TAG) continue;
947
+ if (result !== undefined) continue;
948
+ var raw = (_tag_getCommentText = tag.getCommentText()) === null || _tag_getCommentText === void 0 ? void 0 : _tag_getCommentText.trim();
949
+ if (raw === undefined || raw.length === 0) continue;
950
+ var firstToken = raw.split(/\s+/)[0];
951
+ if (TOOL_NAME_SEGMENT_PATTERN.test(firstToken)) {
952
+ result = firstToken;
953
+ }
954
+ }
955
+ } catch (err) {
956
+ _didIteratorError1 = true;
957
+ _iteratorError1 = err;
958
+ } finally{
959
+ try {
960
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
961
+ _iterator1.return();
962
+ }
963
+ } finally{
964
+ if (_didIteratorError1) {
965
+ throw _iteratorError1;
966
+ }
967
+ }
968
+ }
969
+ }
970
+ } catch (err) {
971
+ _didIteratorError = true;
972
+ _iteratorError = err;
973
+ } finally{
974
+ try {
975
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
976
+ _iterator.return();
977
+ }
978
+ } finally{
979
+ if (_didIteratorError) {
980
+ throw _iteratorError;
981
+ }
982
+ }
983
+ }
984
+ return result;
985
+ }
852
986
  function readDbxModelReadTag(jsDocs) {
853
987
  var result;
854
988
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -55,6 +55,11 @@ var SUPPORTED_VERBS = new Set([
55
55
  'query',
56
56
  'invoke'
57
57
  ]);
58
+ /**
59
+ * JSDoc tag (without leading `@`) on a CRUD leaf naming the interface that a handler's
60
+ * `mapSuccessfulResult` produces for MCP. When present, the MCP manifest output schema is
61
+ * synthesized from this type instead of the raw result type.
62
+ */ var DBX_MODEL_API_MCP_RESULT_MARKER = 'dbxModelApiMcpResult';
58
63
  /**
59
64
  * Walks a `<model>.api.ts` source and returns one {@link CrudEntry} per
60
65
  * callable leaf (CRUD or standalone). Best-effort: malformed configs return
@@ -134,6 +139,7 @@ function extractCrudEntries(source) {
134
139
  valueNode: verbValueNode,
135
140
  entries: entries,
136
141
  fallbackDescription: readJsDocSummary(verbMember),
142
+ fallbackMcpResultTypeName: readJsDocTagValue(verbMember, DBX_MODEL_API_MCP_RESULT_MARKER),
137
143
  resolveTypeDocs: resolveTypeDocs
138
144
  });
139
145
  }
@@ -185,6 +191,8 @@ function extractCrudEntries(source) {
185
191
  var tuple = valueNode1 ? readTupleParamsResult(valueNode1) : undefined;
186
192
  var paramsDocs = resolveTypeDocs(tuple === null || tuple === void 0 ? void 0 : tuple.params);
187
193
  var resultDocs = resolveTypeDocs(tuple === null || tuple === void 0 ? void 0 : tuple.result);
194
+ var mcpResultTypeName = readJsDocTagValue(member1, DBX_MODEL_API_MCP_RESULT_MARKER);
195
+ var mcpResultDocs = resolveTypeDocs(mcpResultTypeName);
188
196
  entries.push({
189
197
  model: key,
190
198
  verb: 'standalone',
@@ -197,7 +205,10 @@ function extractCrudEntries(source) {
197
205
  paramsFields: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.fields,
198
206
  paramsHasApiParamsTag: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.hasApiParamsTag,
199
207
  resultTypeDescription: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.typeDescription,
200
- resultFields: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.fields
208
+ resultFields: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.fields,
209
+ mcpResultTypeName: mcpResultTypeName,
210
+ mcpResultTypeDescription: mcpResultDocs === null || mcpResultDocs === void 0 ? void 0 : mcpResultDocs.typeDescription,
211
+ mcpResultFields: mcpResultDocs === null || mcpResultDocs === void 0 ? void 0 : mcpResultDocs.fields
201
212
  });
202
213
  }
203
214
  } catch (err) {
@@ -353,7 +364,7 @@ function isNullLiteralType(node) {
353
364
  }
354
365
  function collectVerbEntries(input) {
355
366
  var _readTupleParamsResult;
356
- var modelName = input.modelName, verb = input.verb, valueNode = input.valueNode, entries = input.entries, fallbackDescription = input.fallbackDescription, resolveTypeDocs = input.resolveTypeDocs;
367
+ var modelName = input.modelName, verb = input.verb, valueNode = input.valueNode, entries = input.entries, fallbackDescription = input.fallbackDescription, fallbackMcpResultTypeName = input.fallbackMcpResultTypeName, resolveTypeDocs = input.resolveTypeDocs;
357
368
  if (Node.isTypeLiteral(valueNode)) {
358
369
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
359
370
  try {
@@ -368,6 +379,8 @@ function collectVerbEntries(input) {
368
379
  var leaf = leafNode ? (_readTupleParamsResult1 = readTupleParamsResult(leafNode)) !== null && _readTupleParamsResult1 !== void 0 ? _readTupleParamsResult1 : readBareParams(leafNode) : undefined;
369
380
  var paramsDocs = resolveTypeDocs(leaf === null || leaf === void 0 ? void 0 : leaf.params);
370
381
  var resultDocs = resolveTypeDocs(leaf === null || leaf === void 0 ? void 0 : leaf.result);
382
+ var mcpResultTypeName = readJsDocTagValue(specMember, DBX_MODEL_API_MCP_RESULT_MARKER);
383
+ var mcpResultDocs = resolveTypeDocs(mcpResultTypeName);
371
384
  entries.push({
372
385
  model: modelName,
373
386
  verb: verb,
@@ -380,7 +393,10 @@ function collectVerbEntries(input) {
380
393
  paramsFields: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.fields,
381
394
  paramsHasApiParamsTag: paramsDocs === null || paramsDocs === void 0 ? void 0 : paramsDocs.hasApiParamsTag,
382
395
  resultTypeDescription: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.typeDescription,
383
- resultFields: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.fields
396
+ resultFields: resultDocs === null || resultDocs === void 0 ? void 0 : resultDocs.fields,
397
+ mcpResultTypeName: mcpResultTypeName,
398
+ mcpResultTypeDescription: mcpResultDocs === null || mcpResultDocs === void 0 ? void 0 : mcpResultDocs.typeDescription,
399
+ mcpResultFields: mcpResultDocs === null || mcpResultDocs === void 0 ? void 0 : mcpResultDocs.fields
384
400
  });
385
401
  }
386
402
  } catch (err) {
@@ -402,6 +418,7 @@ function collectVerbEntries(input) {
402
418
  var leaf1 = (_readTupleParamsResult = readTupleParamsResult(valueNode)) !== null && _readTupleParamsResult !== void 0 ? _readTupleParamsResult : readBareParams(valueNode);
403
419
  var paramsDocs1 = resolveTypeDocs(leaf1 === null || leaf1 === void 0 ? void 0 : leaf1.params);
404
420
  var resultDocs1 = resolveTypeDocs(leaf1 === null || leaf1 === void 0 ? void 0 : leaf1.result);
421
+ var mcpResultDocs1 = resolveTypeDocs(fallbackMcpResultTypeName);
405
422
  entries.push({
406
423
  model: modelName,
407
424
  verb: verb,
@@ -414,7 +431,10 @@ function collectVerbEntries(input) {
414
431
  paramsFields: paramsDocs1 === null || paramsDocs1 === void 0 ? void 0 : paramsDocs1.fields,
415
432
  paramsHasApiParamsTag: paramsDocs1 === null || paramsDocs1 === void 0 ? void 0 : paramsDocs1.hasApiParamsTag,
416
433
  resultTypeDescription: resultDocs1 === null || resultDocs1 === void 0 ? void 0 : resultDocs1.typeDescription,
417
- resultFields: resultDocs1 === null || resultDocs1 === void 0 ? void 0 : resultDocs1.fields
434
+ resultFields: resultDocs1 === null || resultDocs1 === void 0 ? void 0 : resultDocs1.fields,
435
+ mcpResultTypeName: fallbackMcpResultTypeName,
436
+ mcpResultTypeDescription: mcpResultDocs1 === null || mcpResultDocs1 === void 0 ? void 0 : mcpResultDocs1.typeDescription,
437
+ mcpResultFields: mcpResultDocs1 === null || mcpResultDocs1 === void 0 ? void 0 : mcpResultDocs1.fields
418
438
  });
419
439
  }
420
440
  function readTupleParamsResult(node) {
@@ -567,6 +587,64 @@ function readTypeDocs(sourceFile, typeName) {
567
587
  }
568
588
  return result;
569
589
  }
590
+ /**
591
+ * Reads the value token of a JSDoc tag (e.g. the `Foo` in `@dbxModelApiMcpResult Foo`).
592
+ *
593
+ * Used for value-carrying tags like `@dbxModelApiMcpResult` where the first token after the tag
594
+ * name names a type. Returns the first whitespace-delimited token of the tag's comment text.
595
+ *
596
+ * @param node - Any JSDocable ts-morph node (property signature, etc.).
597
+ * @param tagName - Tag name without the leading `@` (e.g. `'dbxModelApiMcpResult'`).
598
+ * @returns The first token of the tag's value, or `undefined` when the tag is absent or empty.
599
+ */ function readJsDocTagValue(node, tagName) {
600
+ var result;
601
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
602
+ try {
603
+ for(var _iterator = node.getJsDocs()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
604
+ var doc = _step.value;
605
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
606
+ try {
607
+ for(var _iterator1 = doc.getTags()[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
608
+ var tag = _step1.value;
609
+ if (tag.getTagName() === tagName) {
610
+ var _tag_getCommentText;
611
+ var token = (_tag_getCommentText = tag.getCommentText()) === null || _tag_getCommentText === void 0 ? void 0 : _tag_getCommentText.trim().split(/\s+/)[0];
612
+ if (token) {
613
+ result = token;
614
+ }
615
+ }
616
+ }
617
+ } catch (err) {
618
+ _didIteratorError1 = true;
619
+ _iteratorError1 = err;
620
+ } finally{
621
+ try {
622
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
623
+ _iterator1.return();
624
+ }
625
+ } finally{
626
+ if (_didIteratorError1) {
627
+ throw _iteratorError1;
628
+ }
629
+ }
630
+ }
631
+ }
632
+ } catch (err) {
633
+ _didIteratorError = true;
634
+ _iteratorError = err;
635
+ } finally{
636
+ try {
637
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
638
+ _iterator.return();
639
+ }
640
+ } finally{
641
+ if (_didIteratorError) {
642
+ throw _iteratorError;
643
+ }
644
+ }
645
+ }
646
+ return result;
647
+ }
570
648
  function readJsDocSummary(node) {
571
649
  var result;
572
650
  var docs = node.getJsDocs();
@@ -615,7 +693,9 @@ var READ_LEVEL_VALUES = new Set([
615
693
  'permissions'
616
694
  ]);
617
695
  var SERVICE_FACTORY_TAG = 'dbxModelServiceFactory';
696
+ var MCP_TOOL_NAME_SEGMENT_TAG = 'dbxModelMcpToolNameSegment';
618
697
  var MODEL_TYPE_VALUE_PATTERN = /^[a-z][A-Za-z0-9_$]*$/;
698
+ var TOOL_NAME_SEGMENT_PATTERN = /^[A-Za-z][A-Za-z0-9_$]*$/;
619
699
  /**
620
700
  * TS utility/structural wrappers that don't change the field surface for
621
701
  * inheritance walks — `Partial<T>`, `Required<T>`, `Readonly<T>`,
@@ -801,6 +881,7 @@ function buildInterface(decl) {
801
881
  var jsDocs = decl.getJsDocs();
802
882
  var hasDbxModelTag = jsDocsHaveTag(jsDocs, 'dbxModel');
803
883
  var dbxModelRead = readDbxModelReadTag(jsDocs);
884
+ var mcpToolNameSegment = readMcpToolNameSegmentTag(jsDocs);
804
885
  var extendsNames = decl.getExtends().map(resolveExtendsName);
805
886
  var props = [];
806
887
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -845,8 +926,61 @@ function buildInterface(decl) {
845
926
  props: props
846
927
  }, dbxModelRead === undefined ? {} : {
847
928
  dbxModelRead: dbxModelRead
929
+ }, mcpToolNameSegment === undefined ? {} : {
930
+ mcpToolNameSegment: mcpToolNameSegment
848
931
  });
849
932
  }
933
+ function readMcpToolNameSegmentTag(jsDocs) {
934
+ var result;
935
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
936
+ try {
937
+ for(var _iterator = jsDocs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
938
+ var doc = _step.value;
939
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
940
+ try {
941
+ for(var _iterator1 = doc.getTags()[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
942
+ var tag = _step1.value;
943
+ var _tag_getCommentText;
944
+ if (tag.getTagName() !== MCP_TOOL_NAME_SEGMENT_TAG) continue;
945
+ if (result !== undefined) continue;
946
+ var raw = (_tag_getCommentText = tag.getCommentText()) === null || _tag_getCommentText === void 0 ? void 0 : _tag_getCommentText.trim();
947
+ if (raw === undefined || raw.length === 0) continue;
948
+ var firstToken = raw.split(/\s+/)[0];
949
+ if (TOOL_NAME_SEGMENT_PATTERN.test(firstToken)) {
950
+ result = firstToken;
951
+ }
952
+ }
953
+ } catch (err) {
954
+ _didIteratorError1 = true;
955
+ _iteratorError1 = err;
956
+ } finally{
957
+ try {
958
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
959
+ _iterator1.return();
960
+ }
961
+ } finally{
962
+ if (_didIteratorError1) {
963
+ throw _iteratorError1;
964
+ }
965
+ }
966
+ }
967
+ }
968
+ } catch (err) {
969
+ _didIteratorError = true;
970
+ _iteratorError = err;
971
+ } finally{
972
+ try {
973
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
974
+ _iterator.return();
975
+ }
976
+ } finally{
977
+ if (_didIteratorError) {
978
+ throw _iteratorError;
979
+ }
980
+ }
981
+ }
982
+ return result;
983
+ }
850
984
  function readDbxModelReadTag(jsDocs) {
851
985
  var result;
852
986
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli/manifest-extract",
3
- "version": "13.13.0",
3
+ "version": "13.15.0",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "ts-morph": "^21.0.0"
7
7
  },
8
8
  "devDependencies": {
9
- "@dereekb/firebase": "13.13.0"
9
+ "@dereekb/firebase": "13.15.0"
10
10
  },
11
11
  "exports": {
12
12
  "./package.json": "./package.json",
@@ -77,6 +77,20 @@ export interface CrudEntry {
77
77
  * Per-field JSDocs read from the result interface's properties.
78
78
  */
79
79
  readonly resultFields?: readonly CrudEntryDocField[];
80
+ /**
81
+ * Name of the MCP-mapped result interface declared via the `@dbxModelApiMcpResult <TypeName>`
82
+ * JSDoc tag on the leaf. Present only when a handler remaps its success result for MCP; the
83
+ * MCP manifest output schema is synthesized from this type instead of the raw result.
84
+ */
85
+ readonly mcpResultTypeName?: string;
86
+ /**
87
+ * JSDoc summary on the MCP-mapped result interface itself (resolved from `mcpResultTypeName`).
88
+ */
89
+ readonly mcpResultTypeDescription?: string;
90
+ /**
91
+ * Per-field JSDocs read from the MCP-mapped result interface's properties.
92
+ */
93
+ readonly mcpResultFields?: readonly CrudEntryDocField[];
80
94
  }
81
95
  export interface CrudExtraction {
82
96
  /**
@@ -142,6 +156,11 @@ export interface ModelExtractionInterface {
142
156
  * / `permissions`). Absent when the interface omits the tag or declares an invalid value.
143
157
  */
144
158
  readonly dbxModelRead?: 'system' | 'owner' | 'admin-only' | 'permissions';
159
+ /**
160
+ * Per-model MCP tool-name segment from `@dbxModelMcpToolNameSegment <segment>`. Replaces the model
161
+ * type in generated tool names (e.g. the collection prefix). Absent when the tag is omitted or invalid.
162
+ */
163
+ readonly mcpToolNameSegment?: string;
145
164
  }
146
165
  /**
147
166
  * One field inside a converter's `fields` map.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli",
3
- "version": "13.13.0",
3
+ "version": "13.15.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "bin": {
@@ -28,12 +28,21 @@
28
28
  "import": "./manifest-extract/index.cjs.mjs",
29
29
  "default": "./manifest-extract/index.cjs.js"
30
30
  },
31
+ "./model-test": {
32
+ "module": "./model-test/index.esm.js",
33
+ "types": "./model-test/index.d.ts",
34
+ "import": "./model-test/index.cjs.mjs",
35
+ "default": "./model-test/index.cjs.js"
36
+ },
31
37
  "./test": {
32
38
  "module": "./test/index.esm.js",
33
39
  "types": "./test/index.d.ts",
34
40
  "import": "./test/index.cjs.mjs",
35
41
  "default": "./test/index.cjs.js"
36
42
  },
43
+ "./validate": {
44
+ "default": "./validate/index.js"
45
+ },
37
46
  "./package.json": "./package.json",
38
47
  ".": {
39
48
  "import": "./index.esm.js",
@@ -41,11 +50,11 @@
41
50
  }
42
51
  },
43
52
  "peerDependencies": {
44
- "@dereekb/date": "13.13.0",
45
- "@dereekb/firebase": "13.13.0",
46
- "@dereekb/model": "13.13.0",
47
- "@dereekb/nestjs": "13.13.0",
48
- "@dereekb/util": "13.13.0",
53
+ "@dereekb/date": "13.15.0",
54
+ "@dereekb/firebase": "13.15.0",
55
+ "@dereekb/model": "13.15.0",
56
+ "@dereekb/nestjs": "13.15.0",
57
+ "@dereekb/util": "13.15.0",
49
58
  "@nestjs/common": "^11.1.19",
50
59
  "arktype": "^2.2.0",
51
60
  "jiti": "2.6.1",