vona-cli-set-api 1.1.179 → 1.1.181

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.
@@ -3,7 +3,7 @@ import type { IQueryParams, TypeAnalysisGroupParams, TypeAnalysisAggregateParams
3
3
  import type { IDecoratorControllerOptions } from 'vona-module-a-web';
4
4
 
5
5
  import { BeanBase } from 'vona';
6
- import { Api, Resource, v } from 'vona-module-a-openapiutils';
6
+ import { Api, Mcp, Resource, v } from 'vona-module-a-openapiutils';
7
7
  import { z } from 'zod';
8
8
  import { Passport } from 'vona-module-a-user';
9
9
  import { Arg, Controller, Web } from 'vona-module-a-web';
@@ -28,6 +28,10 @@ export interface IControllerOptions<%=argv.resourceNameCapitalize%> extends IDec
28
28
  })
29
29
  @Resource()
30
30
  export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
31
+ @Mcp.tool({
32
+ description: $locale('<%=argv.resourceNameCapitalize%>CreateDescription'),
33
+ readOnly: false,
34
+ })
31
35
  @Web.post('', { summary: $locale('<%=argv.resourceNameCapitalize%>Create') })
32
36
  @Api.body(v.tableIdentity())
33
37
  @Passport.rbac()
@@ -35,6 +39,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
35
39
  return (await this.scope.service.<%=argv.resourceName%>.create(<%=argv.resourceName%>)).id;
36
40
  }
37
41
 
42
+ @Mcp.tool({
43
+ description: $locale('<%=argv.resourceNameCapitalize%>SelectDescription'),
44
+ readOnly: true,
45
+ })
38
46
  @Web.get('', { summary: $locale('<%=argv.resourceNameCapitalize%>Select') })
39
47
  @Api.body(Dto<%=argv.resourceNameCapitalize%>SelectRes)
40
48
  @Passport.rbac()
@@ -42,6 +50,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
42
50
  return await this.scope.service.<%=argv.resourceName%>.select(params);
43
51
  }
44
52
 
53
+ @Mcp.tool({
54
+ description: $locale('<%=argv.resourceNameCapitalize%>GroupDescription'),
55
+ readOnly: true,
56
+ })
45
57
  @Web.get('group', { summary: $locale('<%=argv.resourceNameCapitalize%>Group') })
46
58
  @Api.body(v.array(v.object(Dto<%=argv.resourceNameCapitalize%>GroupResItem)))
47
59
  @Passport.rbac({ actionInherit: 'select' })
@@ -49,6 +61,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
49
61
  return await this.scope.service.<%=argv.resourceName%>.group(params);
50
62
  }
51
63
 
64
+ @Mcp.tool({
65
+ description: $locale('<%=argv.resourceNameCapitalize%>AggregateDescription'),
66
+ readOnly: true,
67
+ })
52
68
  @Web.get('aggregate', { summary: $locale('<%=argv.resourceNameCapitalize%>Aggregate') })
53
69
  @Api.body(Dto<%=argv.resourceNameCapitalize%>AggregateRes)
54
70
  @Passport.rbac({ actionInherit: 'select' })
@@ -56,6 +72,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
56
72
  return await this.scope.service.<%=argv.resourceName%>.aggregate(params);
57
73
  }
58
74
 
75
+ @Mcp.tool({
76
+ description: $locale('<%=argv.resourceNameCapitalize%>ViewDescription'),
77
+ readOnly: true,
78
+ })
59
79
  @Web.get(':id', { summary: $locale('<%=argv.resourceNameCapitalize%>View') })
60
80
  @Api.body(v.optional(), v.object(Dto<%=argv.resourceNameCapitalize%>View))
61
81
  @Passport.rbac()
@@ -63,6 +83,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
63
83
  return await this.scope.service.<%=argv.resourceName%>.view(id);
64
84
  }
65
85
 
86
+ @Mcp.tool({
87
+ description: $locale('<%=argv.resourceNameCapitalize%>UpdateDescription'),
88
+ readOnly: false,
89
+ })
66
90
  @Web.patch(':id', { summary: $locale('<%=argv.resourceNameCapitalize%>Update') })
67
91
  @Api.body(z.null())
68
92
  @Passport.rbac()
@@ -70,6 +94,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
70
94
  await this.scope.service.<%=argv.resourceName%>.update(id, <%=argv.resourceName%>);
71
95
  }
72
96
 
97
+ @Mcp.tool({
98
+ description: $locale('<%=argv.resourceNameCapitalize%>DeleteDescription'),
99
+ readOnly: false,
100
+ })
73
101
  @Web.delete(':id', { summary: $locale('<%=argv.resourceNameCapitalize%>Delete') })
74
102
  @Api.body(z.null())
75
103
  @Passport.rbac()
@@ -77,6 +105,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
77
105
  await this.scope.service.<%=argv.resourceName%>.delete(id);
78
106
  }
79
107
 
108
+ @Mcp.tool({
109
+ description: $locale('<%=argv.resourceNameCapitalize%>DeleteBulkDescription'),
110
+ readOnly: false,
111
+ })
80
112
  @Web.post('bulk/delete', { summary: $locale('<%=argv.resourceNameCapitalize%>DeleteBulk') })
81
113
  @Api.body(z.null())
82
114
  @Passport.rbac({ actionInherit: 'delete' })
@@ -42,6 +42,14 @@ export default metadataCustomSnippet({
42
42
  [`${resource}DeleteBulk`]: `Bulk Delete ${resource}`,
43
43
  [`${resource}Group`]: `Group ${resource}`,
44
44
  [`${resource}Aggregate`]: `Aggregate ${resource}`,
45
+ [`${resource}CreateDescription`]: `Create ${resource}.`,
46
+ [`${resource}SelectDescription`]: `Query the ${resource} list.`,
47
+ [`${resource}GroupDescription`]: `Group ${resource} records.`,
48
+ [`${resource}AggregateDescription`]: `Aggregate ${resource} records.`,
49
+ [`${resource}ViewDescription`]: `View a ${resource} by ID.`,
50
+ [`${resource}UpdateDescription`]: `Update a ${resource} by ID.`,
51
+ [`${resource}DeleteDescription`]: `Delete a ${resource} by ID.`,
52
+ [`${resource}DeleteBulkDescription`]: `Delete multiple ${resource} records by ID.`,
45
53
  };
46
54
  return locale_transform({ ast, argv, resources });
47
55
  },
@@ -25,6 +25,14 @@ export default metadataCustomSnippet({
25
25
  [`${resource}DeleteBulk`]: `批量删除${resource}`,
26
26
  [`${resource}Group`]: `${resource}分组统计`,
27
27
  [`${resource}Aggregate`]: `${resource}汇总统计`,
28
+ [`${resource}CreateDescription`]: `创建${resource}。`,
29
+ [`${resource}SelectDescription`]: `查询${resource}列表。`,
30
+ [`${resource}GroupDescription`]: `对${resource}进行分组统计。`,
31
+ [`${resource}AggregateDescription`]: `对${resource}进行汇总统计。`,
32
+ [`${resource}ViewDescription`]: `按 ID 查看${resource}。`,
33
+ [`${resource}UpdateDescription`]: `按 ID 更新${resource}。`,
34
+ [`${resource}DeleteDescription`]: `按 ID 删除${resource}。`,
35
+ [`${resource}DeleteBulkDescription`]: `按 ID 批量删除${resource}。`,
28
36
  };
29
37
  return locale_transform({ ast, argv, resources });
30
38
  },
@@ -10,6 +10,18 @@ export async function locale_transform({
10
10
  resources: any;
11
11
  }) {
12
12
  const values = evaluateSimple(ast.replace('export default', '').replace(';', ''));
13
+ const pendingDescriptions = new Set(
14
+ [...ast.matchAll(/^\s*\/\/ TODO\(mcp-description\): (\w+) -.*$/gm)].map(match => match[1]),
15
+ );
16
+ for (const key of Object.keys(resources)) {
17
+ if (
18
+ key.startsWith(argv.resourceNameCapitalize) &&
19
+ key.endsWith('Description') &&
20
+ !Object.hasOwn(values, key)
21
+ ) {
22
+ pendingDescriptions.add(key);
23
+ }
24
+ }
13
25
  resources = Object.assign(
14
26
  {},
15
27
  resources,
@@ -19,6 +31,9 @@ export async function locale_transform({
19
31
  const keys = Object.keys(resources).sort();
20
32
  let content = '';
21
33
  for (const key of keys) {
34
+ if (pendingDescriptions.has(key)) {
35
+ content += ` // TODO(mcp-description): ${key} - refine using the actual Action, DTO and Service behavior.\n`;
36
+ }
22
37
  content += ` ${key}: '${resources[key].replaceAll("'", "\\'")}',\n`;
23
38
  }
24
39
  ast = `export default {\n${content}};\n`;
@@ -4,7 +4,7 @@ import type { IRbacScopeAccess } from 'vona-module-a-rbac';
4
4
  import type { IDecoratorControllerOptions } from 'vona-module-a-web';
5
5
 
6
6
  import { BeanBase } from 'vona';
7
- import { Api, Resource, v } from 'vona-module-a-openapiutils';
7
+ import { Api, Mcp, Resource, v } from 'vona-module-a-openapiutils';
8
8
  import { z } from 'zod';
9
9
  import { Passport } from 'vona-module-a-user';
10
10
  import { Arg, Controller, Web } from 'vona-module-a-web';
@@ -29,6 +29,10 @@ export interface IControllerOptions<%=argv.resourceNameCapitalize%> extends IDec
29
29
  })
30
30
  @Resource()
31
31
  export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
32
+ @Mcp.tool({
33
+ description: $locale('<%=argv.resourceNameCapitalize%>CreateDescription'),
34
+ readOnly: false,
35
+ })
32
36
  @Web.post('', { summary: $locale('<%=argv.resourceNameCapitalize%>Create') })
33
37
  @Api.body(v.tableIdentity())
34
38
  @Passport.rbac()
@@ -36,6 +40,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
36
40
  return (await this.scope.service.<%=argv.resourceName%>.create(<%=argv.resourceName%>)).id;
37
41
  }
38
42
 
43
+ @Mcp.tool({
44
+ description: $locale('<%=argv.resourceNameCapitalize%>SelectDescription'),
45
+ readOnly: true,
46
+ })
39
47
  @Web.get('', { summary: $locale('<%=argv.resourceNameCapitalize%>Select') })
40
48
  @Api.body(Dto<%=argv.resourceNameCapitalize%>SelectRes)
41
49
  @Passport.rbac()
@@ -43,6 +51,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
43
51
  return await this.scope.service.<%=argv.resourceName%>.select(params);
44
52
  }
45
53
 
54
+ @Mcp.tool({
55
+ description: $locale('<%=argv.resourceNameCapitalize%>GroupDescription'),
56
+ readOnly: true,
57
+ })
46
58
  @Web.get('group', { summary: $locale('<%=argv.resourceNameCapitalize%>Group') })
47
59
  @Api.body(v.array(v.object(Dto<%=argv.resourceNameCapitalize%>GroupResItem)))
48
60
  @Passport.rbac({ actionInherit: 'select' })
@@ -50,6 +62,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
50
62
  return await this.scope.service.<%=argv.resourceName%>.group(params);
51
63
  }
52
64
 
65
+ @Mcp.tool({
66
+ description: $locale('<%=argv.resourceNameCapitalize%>AggregateDescription'),
67
+ readOnly: true,
68
+ })
53
69
  @Web.get('aggregate', { summary: $locale('<%=argv.resourceNameCapitalize%>Aggregate') })
54
70
  @Api.body(Dto<%=argv.resourceNameCapitalize%>AggregateRes)
55
71
  @Passport.rbac({ actionInherit: 'select' })
@@ -57,6 +73,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
57
73
  return await this.scope.service.<%=argv.resourceName%>.aggregate(params);
58
74
  }
59
75
 
76
+ @Mcp.tool({
77
+ description: $locale('<%=argv.resourceNameCapitalize%>ViewDescription'),
78
+ readOnly: true,
79
+ })
60
80
  @Web.get(':id', { summary: $locale('<%=argv.resourceNameCapitalize%>View') })
61
81
  @Api.body(v.optional(), v.object(Dto<%=argv.resourceNameCapitalize%>View))
62
82
  @Passport.rbac()
@@ -64,6 +84,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
64
84
  return await this.scope.service.<%=argv.resourceName%>.view(id);
65
85
  }
66
86
 
87
+ @Mcp.tool({
88
+ description: $locale('<%=argv.resourceNameCapitalize%>UpdateDescription'),
89
+ readOnly: false,
90
+ })
67
91
  @Web.patch(':id', { summary: $locale('<%=argv.resourceNameCapitalize%>Update') })
68
92
  @Api.body(z.null())
69
93
  @Passport.rbac()
@@ -71,6 +95,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
71
95
  await this.scope.service.<%=argv.resourceName%>.update(id, <%=argv.resourceName%>);
72
96
  }
73
97
 
98
+ @Mcp.tool({
99
+ description: $locale('<%=argv.resourceNameCapitalize%>DeleteDescription'),
100
+ readOnly: false,
101
+ })
74
102
  @Web.delete(':id', { summary: $locale('<%=argv.resourceNameCapitalize%>Delete') })
75
103
  @Api.body(z.null())
76
104
  @Passport.rbac()
@@ -78,6 +106,10 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
78
106
  await this.scope.service.<%=argv.resourceName%>.delete(id);
79
107
  }
80
108
 
109
+ @Mcp.tool({
110
+ description: $locale('<%=argv.resourceNameCapitalize%>DeleteBulkDescription'),
111
+ readOnly: false,
112
+ })
81
113
  @Web.post('bulk/delete', { summary: $locale('BulkDelete') })
82
114
  @Api.body(z.null())
83
115
  @Passport.rbac({ actionInherit: 'delete' })
@@ -42,6 +42,14 @@ export default metadataCustomSnippet({
42
42
  [`${resource}Delete`]: `Delete ${resource}`,
43
43
  [`${resource}Group`]: `Group ${resource}`,
44
44
  [`${resource}Aggregate`]: `Aggregate ${resource}`,
45
+ [`${resource}CreateDescription`]: `Create ${resource}.`,
46
+ [`${resource}SelectDescription`]: `Query the ${resource} list.`,
47
+ [`${resource}GroupDescription`]: `Group ${resource} records.`,
48
+ [`${resource}AggregateDescription`]: `Aggregate ${resource} records.`,
49
+ [`${resource}ViewDescription`]: `View a ${resource} by ID.`,
50
+ [`${resource}UpdateDescription`]: `Update a ${resource} by ID.`,
51
+ [`${resource}DeleteDescription`]: `Delete a ${resource} by ID.`,
52
+ [`${resource}DeleteBulkDescription`]: `Delete multiple ${resource} records by ID.`,
45
53
  };
46
54
  return locale_transform({ ast, argv, resources });
47
55
  },
@@ -25,6 +25,14 @@ export default metadataCustomSnippet({
25
25
  [`${resource}Delete`]: `删除${resource}`,
26
26
  [`${resource}Group`]: `${resource}分组统计`,
27
27
  [`${resource}Aggregate`]: `${resource}汇总统计`,
28
+ [`${resource}CreateDescription`]: `创建${resource}。`,
29
+ [`${resource}SelectDescription`]: `查询${resource}列表。`,
30
+ [`${resource}GroupDescription`]: `对${resource}进行分组统计。`,
31
+ [`${resource}AggregateDescription`]: `对${resource}进行汇总统计。`,
32
+ [`${resource}ViewDescription`]: `按 ID 查看${resource}。`,
33
+ [`${resource}UpdateDescription`]: `按 ID 更新${resource}。`,
34
+ [`${resource}DeleteDescription`]: `按 ID 删除${resource}。`,
35
+ [`${resource}DeleteBulkDescription`]: `按 ID 批量删除${resource}。`,
28
36
  };
29
37
  return locale_transform({ ast, argv, resources });
30
38
  },
@@ -10,6 +10,18 @@ export async function locale_transform({
10
10
  resources: any;
11
11
  }) {
12
12
  const values = evaluateSimple(ast.replace('export default', '').replace(';', ''));
13
+ const pendingDescriptions = new Set(
14
+ [...ast.matchAll(/^\s*\/\/ TODO\(mcp-description\): (\w+) -.*$/gm)].map(match => match[1]),
15
+ );
16
+ for (const key of Object.keys(resources)) {
17
+ if (
18
+ key.startsWith(argv.resourceNameCapitalize) &&
19
+ key.endsWith('Description') &&
20
+ !Object.hasOwn(values, key)
21
+ ) {
22
+ pendingDescriptions.add(key);
23
+ }
24
+ }
13
25
  resources = Object.assign(
14
26
  {},
15
27
  resources,
@@ -19,6 +31,9 @@ export async function locale_transform({
19
31
  const keys = Object.keys(resources).sort();
20
32
  let content = '';
21
33
  for (const key of keys) {
34
+ if (pendingDescriptions.has(key)) {
35
+ content += ` // TODO(mcp-description): ${key} - refine using the actual Action, DTO and Service behavior.\n`;
36
+ }
22
37
  content += ` ${key}: '${resources[key].replaceAll("'", "\\'")}',\n`;
23
38
  }
24
39
  ast = `export default {\n${content}};\n`;
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import { resolveTestRunId, TEST_RUN_ID_ENV, getTestAppName, requiresFreshTestRes
23
23
  import chalk from 'chalk';
24
24
  import { spawn } from 'node:child_process';
25
25
  import nodemon from 'nodemon';
26
- import { catchError, combineApiPathControllerAndActionRaw, replaceTemplate } from '@cabloy/utils';
26
+ import { catchError, combineApiPathControllerAndActionRaw, evaluateSimple, replaceTemplate } from '@cabloy/utils';
27
27
  import { getOnionScenesMeta, getOnionMetasMeta, relativeNameToCapitalize } from '@cabloy/module-info';
28
28
  import { toUpperCaseFirstChar, stringToCapitalize, replaceTemplate as replaceTemplate$1 } from '@cabloy/word-utils';
29
29
  import fs from 'node:fs';
@@ -2013,6 +2013,7 @@ class CliToolsCrudBasic extends BeanCliBase {
2013
2013
  cwd: argv.projectPath
2014
2014
  });
2015
2015
  }
2016
+ await this.console.log('MCP Actions generated with minimal descriptions, including bulk delete. After implementing the business behavior, refine the descriptions in src/config/locale/*.ts using the actual Action, DTO and Service behavior. Resolve TODO(mcp-description) before completion; report any unresolved descriptions as unfinished.');
2016
2017
  }
2017
2018
  }
2018
2019
 
@@ -2054,6 +2055,7 @@ class CliToolsCrudStart extends BeanCliBase {
2054
2055
  cwd: argv.projectPath
2055
2056
  });
2056
2057
  }
2058
+ await this.console.log('MCP Actions generated with minimal descriptions, including bulk delete. After implementing the business behavior, refine the descriptions in src/config/locale/*.ts using the actual Action, DTO and Service behavior. Resolve TODO(mcp-description) before completion; report any unresolved descriptions as unfinished.');
2057
2059
  }
2058
2060
  }
2059
2061
 
@@ -2237,6 +2239,7 @@ class CliToolsMasterDetail extends BeanCliBase {
2237
2239
  await this._renderMasterDetailDtos();
2238
2240
  await this._patchMasterModule();
2239
2241
  await this._refreshMetadata();
2242
+ await this._reportMcpFollowUp();
2240
2243
  }
2241
2244
  _prepareArgv() {
2242
2245
  const {
@@ -2615,9 +2618,41 @@ class CliToolsMasterDetail extends BeanCliBase {
2615
2618
  const {
2616
2619
  argv
2617
2620
  } = this.context;
2621
+ const existingLocaleKeys = new Map();
2622
+ if (argv.detailMode === 'aggregate') {
2623
+ for (const locale of this._masterLocales()) {
2624
+ const fileName = path.join(this._detailPaths().localeDir, `${locale}.ts`);
2625
+ const content = fs.existsSync(fileName) ? this._readFile(fileName) : 'export default {};';
2626
+ const values = evaluateSimple(content.replace('export default', '').replace(';', ''));
2627
+ existingLocaleKeys.set(locale, new Set(Object.keys(values)));
2628
+ }
2629
+ }
2618
2630
  await this.helper.invokeCli([argv.detailCrudCommand, argv.detailResourceName, `--module=${argv.detailModule}`, '--nometadata'], {
2619
2631
  cwd: argv.projectPath
2620
2632
  });
2633
+ if (argv.detailMode === 'aggregate') {
2634
+ await this._removeGeneratedDetailMcpDescriptions(existingLocaleKeys);
2635
+ }
2636
+ }
2637
+ async _removeGeneratedDetailMcpDescriptions(existingLocaleKeys) {
2638
+ const resource = this.context.argv.detailResourceNameCapitalize;
2639
+ const keys = new Set(['Create', 'Select', 'Group', 'Aggregate', 'View', 'Update', 'Delete', 'DeleteBulk'].map(action => `${resource}${action}Description`));
2640
+ for (const [locale, existingKeys] of existingLocaleKeys) {
2641
+ const fileName = path.join(this._detailPaths().localeDir, `${locale}.ts`);
2642
+ const content = this._readFile(fileName);
2643
+ const updated = content.replace(/^[ \t]*\/\/ TODO\(mcp-description\): (\w+) - refine using the actual Action, DTO and Service behavior\.\r?\n[ \t]*(\w+):\s*'(?:\\.|[^'\\])*',\r?\n/gm, (entry, markerKey, key) => {
2644
+ return markerKey === key && keys.has(key) && !existingKeys.has(key) ? '' : entry;
2645
+ });
2646
+ if (updated !== content) await this._saveFile(fileName, updated);
2647
+ }
2648
+ }
2649
+ async _reportMcpFollowUp() {
2650
+ const {
2651
+ argv
2652
+ } = this.context;
2653
+ const detail = `${argv.detailModule}:${argv.detailResourceName}`;
2654
+ const modeMessage = argv.detailMode === 'aggregate' ? `${detail} has no standalone MCP Actions; the earlier child CRUD description reminder does not apply to removed Actions.` : `Review retained standalone MCP Actions for ${detail}, including the ${argv.fk} ownership context and bulk delete.`;
2655
+ await this.console.log(`Final MCP description follow-up (${argv.detailMode}): ${modeMessage} Review already MCP-enabled parent Actions for ${argv.module}:${argv.resourceName}, especially create/view/update/delete affected by ${argv.relationName}. After implementing business behavior, inspect the actual Action, DTO and Service and refine descriptions in every locale. Review ancestor Actions only where their actual DTO/Service path exposes the changed nested contract. Recheck readOnly; do not assume deleteBulk has the single-delete relation behavior. Preserve authored text and existing MCP opt-in decisions; resolve only completed TODO(mcp-description) entries and report unresolved descriptions as unfinished.`);
2621
2656
  }
2622
2657
  _handleAggregateDetailMode(hasStandaloneSurface) {
2623
2658
  const {
@@ -2665,6 +2700,7 @@ class CliToolsMasterDetail extends BeanCliBase {
2665
2700
  const detailRoot = argv._detailModule.root;
2666
2701
  return {
2667
2702
  root: detailRoot,
2703
+ localeDir: path.join(detailRoot, 'src/config/locale'),
2668
2704
  entity: path.join(detailRoot, 'src/entity', `${argv.detailResourceName}.tsx`),
2669
2705
  model: path.join(detailRoot, 'src/model', `${argv.detailResourceName}.ts`),
2670
2706
  controller: path.join(detailRoot, 'src/controller', `${argv.detailResourceName}.ts`),
@@ -75,6 +75,8 @@ export declare class CliToolsMasterDetail extends BeanCliBase {
75
75
  private _detailDtoClassCapitalize;
76
76
  private _masterLocaleAdditions;
77
77
  private _createDetailCoreResource;
78
+ private _removeGeneratedDetailMcpDescriptions;
79
+ private _reportMcpFollowUp;
78
80
  private _handleAggregateDetailMode;
79
81
  private _handleStandaloneDetailMode;
80
82
  private _detailModuleShape;
@@ -32,6 +32,14 @@ export default metadataCustomSnippet({
32
32
  [`${resource}DeleteBulk`]: `Bulk Delete ${resource}`,
33
33
  [`${resource}Group`]: `Group ${resource}`,
34
34
  [`${resource}Aggregate`]: `Aggregate ${resource}`,
35
+ [`${resource}CreateDescription`]: `Create ${resource}.`,
36
+ [`${resource}SelectDescription`]: `Query the ${resource} list.`,
37
+ [`${resource}GroupDescription`]: `Group ${resource} records.`,
38
+ [`${resource}AggregateDescription`]: `Aggregate ${resource} records.`,
39
+ [`${resource}ViewDescription`]: `View a ${resource} by ID.`,
40
+ [`${resource}UpdateDescription`]: `Update a ${resource} by ID.`,
41
+ [`${resource}DeleteDescription`]: `Delete a ${resource} by ID.`,
42
+ [`${resource}DeleteBulkDescription`]: `Delete multiple ${resource} records by ID.`,
35
43
  };
36
44
  return locale_transform({ ast, argv, resources });
37
45
  },
@@ -22,6 +22,14 @@ export default metadataCustomSnippet({
22
22
  [`${resource}DeleteBulk`]: `批量删除${resource}`,
23
23
  [`${resource}Group`]: `${resource}分组统计`,
24
24
  [`${resource}Aggregate`]: `${resource}汇总统计`,
25
+ [`${resource}CreateDescription`]: `创建${resource}。`,
26
+ [`${resource}SelectDescription`]: `查询${resource}列表。`,
27
+ [`${resource}GroupDescription`]: `对${resource}进行分组统计。`,
28
+ [`${resource}AggregateDescription`]: `对${resource}进行汇总统计。`,
29
+ [`${resource}ViewDescription`]: `按 ID 查看${resource}。`,
30
+ [`${resource}UpdateDescription`]: `按 ID 更新${resource}。`,
31
+ [`${resource}DeleteDescription`]: `按 ID 删除${resource}。`,
32
+ [`${resource}DeleteBulkDescription`]: `按 ID 批量删除${resource}。`,
25
33
  };
26
34
  return locale_transform({ ast, argv, resources });
27
35
  },
@@ -1,10 +1,21 @@
1
1
  import { evaluateSimple } from '@cabloy/utils';
2
2
  export async function locale_transform({ ast, argv, resources, }) {
3
3
  const values = evaluateSimple(ast.replace('export default', '').replace(';', ''));
4
+ const pendingDescriptions = new Set([...ast.matchAll(/^\s*\/\/ TODO\(mcp-description\): (\w+) -.*$/gm)].map(match => match[1]));
5
+ for (const key of Object.keys(resources)) {
6
+ if (key.startsWith(argv.resourceNameCapitalize) &&
7
+ key.endsWith('Description') &&
8
+ !Object.hasOwn(values, key)) {
9
+ pendingDescriptions.add(key);
10
+ }
11
+ }
4
12
  resources = Object.assign({}, resources, { [argv.resourceNameCapitalize]: argv.resourceNameCapitalize }, values);
5
13
  const keys = Object.keys(resources).sort();
6
14
  let content = '';
7
15
  for (const key of keys) {
16
+ if (pendingDescriptions.has(key)) {
17
+ content += ` // TODO(mcp-description): ${key} - refine using the actual Action, DTO and Service behavior.\n`;
18
+ }
8
19
  content += ` ${key}: '${resources[key].replaceAll("'", "\\'")}',\n`;
9
20
  }
10
21
  ast = `export default {\n${content}};\n`;
@@ -32,6 +32,14 @@ export default metadataCustomSnippet({
32
32
  [`${resource}Delete`]: `Delete ${resource}`,
33
33
  [`${resource}Group`]: `Group ${resource}`,
34
34
  [`${resource}Aggregate`]: `Aggregate ${resource}`,
35
+ [`${resource}CreateDescription`]: `Create ${resource}.`,
36
+ [`${resource}SelectDescription`]: `Query the ${resource} list.`,
37
+ [`${resource}GroupDescription`]: `Group ${resource} records.`,
38
+ [`${resource}AggregateDescription`]: `Aggregate ${resource} records.`,
39
+ [`${resource}ViewDescription`]: `View a ${resource} by ID.`,
40
+ [`${resource}UpdateDescription`]: `Update a ${resource} by ID.`,
41
+ [`${resource}DeleteDescription`]: `Delete a ${resource} by ID.`,
42
+ [`${resource}DeleteBulkDescription`]: `Delete multiple ${resource} records by ID.`,
35
43
  };
36
44
  return locale_transform({ ast, argv, resources });
37
45
  },
@@ -22,6 +22,14 @@ export default metadataCustomSnippet({
22
22
  [`${resource}Delete`]: `删除${resource}`,
23
23
  [`${resource}Group`]: `${resource}分组统计`,
24
24
  [`${resource}Aggregate`]: `${resource}汇总统计`,
25
+ [`${resource}CreateDescription`]: `创建${resource}。`,
26
+ [`${resource}SelectDescription`]: `查询${resource}列表。`,
27
+ [`${resource}GroupDescription`]: `对${resource}进行分组统计。`,
28
+ [`${resource}AggregateDescription`]: `对${resource}进行汇总统计。`,
29
+ [`${resource}ViewDescription`]: `按 ID 查看${resource}。`,
30
+ [`${resource}UpdateDescription`]: `按 ID 更新${resource}。`,
31
+ [`${resource}DeleteDescription`]: `按 ID 删除${resource}。`,
32
+ [`${resource}DeleteBulkDescription`]: `按 ID 批量删除${resource}。`,
25
33
  };
26
34
  return locale_transform({ ast, argv, resources });
27
35
  },
@@ -1,10 +1,21 @@
1
1
  import { evaluateSimple } from '@cabloy/utils';
2
2
  export async function locale_transform({ ast, argv, resources, }) {
3
3
  const values = evaluateSimple(ast.replace('export default', '').replace(';', ''));
4
+ const pendingDescriptions = new Set([...ast.matchAll(/^\s*\/\/ TODO\(mcp-description\): (\w+) -.*$/gm)].map(match => match[1]));
5
+ for (const key of Object.keys(resources)) {
6
+ if (key.startsWith(argv.resourceNameCapitalize) &&
7
+ key.endsWith('Description') &&
8
+ !Object.hasOwn(values, key)) {
9
+ pendingDescriptions.add(key);
10
+ }
11
+ }
4
12
  resources = Object.assign({}, resources, { [argv.resourceNameCapitalize]: argv.resourceNameCapitalize }, values);
5
13
  const keys = Object.keys(resources).sort();
6
14
  let content = '';
7
15
  for (const key of keys) {
16
+ if (pendingDescriptions.has(key)) {
17
+ content += ` // TODO(mcp-description): ${key} - refine using the actual Action, DTO and Service behavior.\n`;
18
+ }
8
19
  content += ` ${key}: '${resources[key].replaceAll("'", "\\'")}',\n`;
9
20
  }
10
21
  ast = `export default {\n${content}};\n`;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vona-cli-set-api",
3
- "version": "1.1.179",
4
- "gitHead": "c94b659a5ab1819ad7714ddacb6875c4f8cbc022",
3
+ "version": "1.1.181",
4
+ "gitHead": "d1a9a68c5d48db9bc82945c17984dabbec724d8c",
5
5
  "description": "vona cli-set-api",
6
6
  "keywords": [
7
7
  "framework",
@@ -45,10 +45,10 @@
45
45
  "@babel/plugin-proposal-decorators": "^7.29.0",
46
46
  "@babel/plugin-transform-class-properties": "^7.28.6",
47
47
  "@babel/plugin-transform-typescript": "^7.28.6",
48
- "@cabloy/cli": "^3.1.31",
48
+ "@cabloy/cli": "^3.1.32",
49
49
  "@cabloy/dotenv": "^1.2.9",
50
50
  "@cabloy/extend": "^3.2.8",
51
- "@cabloy/module-glob": "^5.3.19",
51
+ "@cabloy/module-glob": "^5.3.20",
52
52
  "@cabloy/module-info": "^2.0.3",
53
53
  "@cabloy/utils": "^2.1.27",
54
54
  "@cabloy/word-utils": "^2.1.8",
@@ -63,7 +63,7 @@
63
63
  "@rollup/plugin-typescript": "^12.3.0",
64
64
  "@swc-node/register": "^1.12.1",
65
65
  "babel-plugin-transform-typescript-metadata": "^0.3.2",
66
- "babel-plugin-vona-bean-module": "^1.1.11",
66
+ "babel-plugin-vona-bean-module": "^1.1.12",
67
67
  "chalk": "^3.0.0",
68
68
  "cli-table3": "^0.6.5",
69
69
  "compressing": "^1.10.4",
@@ -77,7 +77,7 @@
77
77
  "rollup": "^4.60.1",
78
78
  "urllib": "^4.9.0",
79
79
  "uuid": "^11.1.0",
80
- "vona-core": "^5.1.59",
80
+ "vona-core": "^5.1.61",
81
81
  "why-is-node-running": "^3.2.2",
82
82
  "yargs-parser": "^22.0.0"
83
83
  }