@taocompany/magic-grid-mcp 0.0.0-stage → 0.14.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.
Files changed (40) hide show
  1. package/bin/magic-grid-mcp.js +7 -0
  2. package/bin/mgc.js +2 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +43 -0
  6. package/dist/index.d.ts +8 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +5 -0
  9. package/dist/mcpServer.d.ts +7 -0
  10. package/dist/mcpServer.d.ts.map +1 -0
  11. package/dist/mcpServer.js +105 -0
  12. package/dist/packageVersion.d.ts +3 -0
  13. package/dist/packageVersion.d.ts.map +1 -0
  14. package/dist/packageVersion.js +10 -0
  15. package/dist/resolveManifest.d.ts +25 -0
  16. package/dist/resolveManifest.d.ts.map +1 -0
  17. package/dist/resolveManifest.js +169 -0
  18. package/dist/scan/collectSourceFiles.d.ts +2 -0
  19. package/dist/scan/collectSourceFiles.d.ts.map +1 -0
  20. package/dist/scan/collectSourceFiles.js +30 -0
  21. package/dist/scan/parseMagicGrid.d.ts +18 -0
  22. package/dist/scan/parseMagicGrid.d.ts.map +1 -0
  23. package/dist/scan/parseMagicGrid.js +85 -0
  24. package/dist/tools/findRecipes.d.ts +19 -0
  25. package/dist/tools/findRecipes.d.ts.map +1 -0
  26. package/dist/tools/findRecipes.js +104 -0
  27. package/dist/tools/getComponentApi.d.ts +33 -0
  28. package/dist/tools/getComponentApi.d.ts.map +1 -0
  29. package/dist/tools/getComponentApi.js +115 -0
  30. package/dist/types.d.ts +96 -0
  31. package/dist/types.d.ts.map +1 -0
  32. package/dist/types.js +1 -0
  33. package/dist/validate/propTypeLiteral.d.ts +4 -0
  34. package/dist/validate/propTypeLiteral.d.ts.map +1 -0
  35. package/dist/validate/propTypeLiteral.js +48 -0
  36. package/dist/validate/validateUsage.d.ts +9 -0
  37. package/dist/validate/validateUsage.d.ts.map +1 -0
  38. package/dist/validate/validateUsage.js +342 -0
  39. package/package.json +52 -4
  40. package/README.md +0 -3
@@ -0,0 +1,104 @@
1
+ const STOP = new Set([
2
+ 'a',
3
+ 'an',
4
+ 'the',
5
+ 'and',
6
+ 'or',
7
+ 'to',
8
+ 'for',
9
+ 'with',
10
+ '的',
11
+ '与',
12
+ '和',
13
+ '表格',
14
+ 'magic',
15
+ 'grid',
16
+ ]);
17
+ function tokenize(text) {
18
+ return text
19
+ .toLowerCase()
20
+ .split(/[^\p{L}\p{N}_]+/u)
21
+ .map((t) => t.trim())
22
+ .filter((t) => t.length > 1 && !STOP.has(t));
23
+ }
24
+ function camelToKebab(name) {
25
+ return name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
26
+ }
27
+ function extractUsedProps(code, knownProps) {
28
+ const used = [];
29
+ for (const name of knownProps) {
30
+ const kebab = camelToKebab(name);
31
+ const patterns = [
32
+ new RegExp(`\\b${name}\\b`),
33
+ new RegExp(`:${name}\\s*=`),
34
+ new RegExp(`\\b${kebab}\\s*=`),
35
+ new RegExp(`:${kebab}\\s*=`),
36
+ ];
37
+ if (patterns.some((re) => re.test(code))) {
38
+ used.push(name);
39
+ }
40
+ }
41
+ return used.sort();
42
+ }
43
+ function scoreRecipe(queryTokens, recipe) {
44
+ const docTokens = tokenize(`${recipe.id} ${recipe.intent} ${recipe.code}`);
45
+ const docSet = new Set(docTokens);
46
+ let score = 0;
47
+ for (const t of queryTokens) {
48
+ if (docSet.has(t))
49
+ score += 2;
50
+ else if (docTokens.some((d) => d.includes(t) || t.includes(d)))
51
+ score += 1;
52
+ }
53
+ if (queryTokens.some((t) => recipe.id.includes(t)))
54
+ score += 3;
55
+ return score;
56
+ }
57
+ export function findRecipes(manifest, input) {
58
+ const limit = Math.min(Math.max(input.limit ?? 3, 1), 5);
59
+ const recipes = manifest.recipes ?? [];
60
+ const queryTokens = tokenize(input.intent);
61
+ if (recipes.length === 0) {
62
+ return {
63
+ libraryVersion: manifest.libraryVersion,
64
+ matches: [],
65
+ warn: 'manifest 中无 recipes;请升级 @taocompany/magic-grid 并重新 build。',
66
+ };
67
+ }
68
+ if (queryTokens.length === 0) {
69
+ const fallback = recipes.slice(0, limit);
70
+ const propNames = new Set(manifest.props.map((p) => p.name));
71
+ return {
72
+ libraryVersion: manifest.libraryVersion,
73
+ matches: fallback.map((r) => ({
74
+ id: r.id,
75
+ intent: r.intent,
76
+ score: 0,
77
+ code: r.code,
78
+ propsUsed: extractUsedProps(r.code, propNames),
79
+ })),
80
+ warn: 'intent 过短,返回前几条 recipe 作为兜底。',
81
+ };
82
+ }
83
+ const propNames = new Set(manifest.props.map((p) => p.name));
84
+ const ranked = recipes
85
+ .map((recipe) => ({
86
+ recipe,
87
+ score: scoreRecipe(queryTokens, recipe),
88
+ }))
89
+ .filter((r) => r.score > 0)
90
+ .sort((a, b) => b.score - a.score);
91
+ const top = ranked.length > 0
92
+ ? ranked.slice(0, limit)
93
+ : recipes.slice(0, limit).map((recipe) => ({ recipe, score: 0 }));
94
+ return {
95
+ libraryVersion: manifest.libraryVersion,
96
+ matches: top.map(({ recipe, score }) => ({
97
+ id: recipe.id,
98
+ intent: recipe.intent,
99
+ score,
100
+ code: recipe.code,
101
+ propsUsed: extractUsedProps(recipe.code, propNames),
102
+ })),
103
+ };
104
+ }
@@ -0,0 +1,33 @@
1
+ import type { ResolveManifestResult } from '../types.js';
2
+ export type ComponentApiSection = 'props' | 'emits' | 'slots' | 'api' | 'expose' | 'types' | 'columnDef';
3
+ export interface GetComponentApiInput {
4
+ section?: ComponentApiSection;
5
+ names?: string[];
6
+ query?: string;
7
+ }
8
+ export interface ApiItemBase {
9
+ name: string;
10
+ type?: string;
11
+ default?: string;
12
+ required?: boolean;
13
+ notes?: string;
14
+ signature?: string;
15
+ payloadType?: string;
16
+ kind?: string;
17
+ description?: string;
18
+ }
19
+ export interface GetComponentApiResult {
20
+ libraryVersion: string;
21
+ source: 'manifest' | 'package-parse';
22
+ section: ComponentApiSection;
23
+ items: ApiItemBase[];
24
+ total: number;
25
+ truncated?: boolean;
26
+ versionMismatch?: {
27
+ installed: string;
28
+ manifest: string;
29
+ };
30
+ warn?: string;
31
+ }
32
+ export declare function getComponentApi(resolved: ResolveManifestResult, input?: GetComponentApiInput): GetComponentApiResult;
33
+ //# sourceMappingURL=getComponentApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getComponentApi.d.ts","sourceRoot":"","sources":["../../src/tools/getComponentApi.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAe,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAErE,MAAM,MAAM,mBAAmB,GAC3B,OAAO,GACP,OAAO,GACP,OAAO,GACP,KAAK,GACL,QAAQ,GACR,OAAO,GACP,WAAW,CAAA;AAEf,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,mBAAmB,CAAA;IAC7B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,UAAU,GAAG,eAAe,CAAA;IACpC,OAAO,EAAE,mBAAmB,CAAA;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,eAAe,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAoFD,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,qBAAqB,EAC/B,KAAK,GAAE,oBAAyB,GAC/B,qBAAqB,CAmDvB"}
@@ -0,0 +1,115 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ const MAX_OUTPUT_CHARS = 28_000;
4
+ function readInstalledVersion(packageRoot) {
5
+ try {
6
+ const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
7
+ return pkg.version;
8
+ }
9
+ catch {
10
+ return undefined;
11
+ }
12
+ }
13
+ function matchesFilter(name, notes, names, query) {
14
+ if (names && names.length > 0) {
15
+ const set = new Set(names.map((n) => n.toLowerCase()));
16
+ if (!set.has(name.toLowerCase()))
17
+ return false;
18
+ }
19
+ if (query && query.trim()) {
20
+ const q = query.trim().toLowerCase();
21
+ const hay = `${name} ${notes ?? ''}`.toLowerCase();
22
+ if (!hay.includes(q))
23
+ return false;
24
+ }
25
+ return true;
26
+ }
27
+ function sectionItems(manifest, section) {
28
+ switch (section) {
29
+ case 'props':
30
+ return manifest.props.map((p) => ({
31
+ name: p.name,
32
+ type: p.type,
33
+ default: p.default,
34
+ required: p.required,
35
+ notes: p.notes,
36
+ }));
37
+ case 'emits':
38
+ return (manifest.emits ?? []).map((e) => ({
39
+ name: e.name,
40
+ payloadType: e.payloadType,
41
+ notes: e.notes,
42
+ }));
43
+ case 'slots':
44
+ return (manifest.slots ?? []).map((s) => ({
45
+ name: s.name,
46
+ kind: s.kind,
47
+ description: s.description,
48
+ notes: s.description,
49
+ }));
50
+ case 'api':
51
+ return (manifest.gridApi ?? []).map((m) => ({
52
+ name: m.name,
53
+ signature: m.signature,
54
+ notes: m.notes,
55
+ }));
56
+ case 'expose':
57
+ return (manifest.expose ?? []).map((e) => ({
58
+ name: e.name,
59
+ type: e.type,
60
+ notes: e.notes,
61
+ }));
62
+ case 'columnDef':
63
+ return manifest.columnDef.map((c) => ({
64
+ name: c.name,
65
+ type: c.type,
66
+ notes: c.notes,
67
+ }));
68
+ case 'types':
69
+ return [];
70
+ default:
71
+ return [];
72
+ }
73
+ }
74
+ export function getComponentApi(resolved, input = {}) {
75
+ const { manifest, source, packageRoot } = resolved;
76
+ const section = input.section ?? 'props';
77
+ const installed = readInstalledVersion(packageRoot);
78
+ const versionMismatch = installed && installed !== manifest.libraryVersion
79
+ ? { installed, manifest: manifest.libraryVersion }
80
+ : undefined;
81
+ if (section === 'types') {
82
+ return {
83
+ libraryVersion: manifest.libraryVersion,
84
+ source,
85
+ section,
86
+ items: [],
87
+ total: 0,
88
+ versionMismatch,
89
+ warn: 'types 分片尚未写入 api-manifest;请使用 section=props|columnDef 与 names/query,或阅读 @taocompany/magic-grid/types/core。',
90
+ };
91
+ }
92
+ const all = sectionItems(manifest, section);
93
+ const items = all.filter((item) => matchesFilter(item.name, item.notes ?? item.description, input.names, input.query));
94
+ let payload = {
95
+ libraryVersion: manifest.libraryVersion,
96
+ source,
97
+ section,
98
+ items,
99
+ total: items.length,
100
+ versionMismatch,
101
+ };
102
+ let json = JSON.stringify(payload);
103
+ if (json.length > MAX_OUTPUT_CHARS) {
104
+ const ratio = MAX_OUTPUT_CHARS / json.length;
105
+ const keep = Math.max(5, Math.floor(items.length * ratio * 0.9));
106
+ payload = {
107
+ ...payload,
108
+ items: items.slice(0, keep),
109
+ total: items.length,
110
+ truncated: true,
111
+ warn: `结果过大(${items.length} 项);已截断为 ${keep} 项。请用 names 或 query 缩小范围。`,
112
+ };
113
+ }
114
+ return payload;
115
+ }
@@ -0,0 +1,96 @@
1
+ export interface ManifestRuleMeta {
2
+ id: string;
3
+ severity: 'error' | 'warning';
4
+ autoFix: boolean;
5
+ detectable?: 'literal-only' | 'heuristic' | 'static';
6
+ }
7
+ export interface CommonMistake {
8
+ wrong: string;
9
+ right: string;
10
+ kind: 'prop' | 'columnDef';
11
+ }
12
+ export interface ManifestProp {
13
+ name: string;
14
+ type?: string;
15
+ default?: string;
16
+ required?: boolean;
17
+ notes?: string;
18
+ }
19
+ export interface ManifestEmit {
20
+ name: string;
21
+ payloadType?: string;
22
+ notes?: string;
23
+ }
24
+ export interface ManifestSlot {
25
+ name: string;
26
+ kind?: string;
27
+ description?: string;
28
+ }
29
+ export interface ManifestGridApiMethod {
30
+ name: string;
31
+ signature?: string;
32
+ notes?: string;
33
+ }
34
+ export interface ManifestExposeField {
35
+ name: string;
36
+ type?: string;
37
+ notes?: string;
38
+ }
39
+ export interface ManifestColumnDefField {
40
+ name: string;
41
+ type?: string;
42
+ notes?: string;
43
+ }
44
+ export interface ManifestRecipe {
45
+ id: string;
46
+ intent: string;
47
+ code: string;
48
+ }
49
+ export interface ApiManifest {
50
+ manifestVersion: number;
51
+ libraryVersion: string;
52
+ props: ManifestProp[];
53
+ emits?: ManifestEmit[];
54
+ slots?: ManifestSlot[];
55
+ expose?: ManifestExposeField[];
56
+ gridApi?: ManifestGridApiMethod[];
57
+ columnDef: ManifestColumnDefField[];
58
+ rules: ManifestRuleMeta[];
59
+ commonMistakes: CommonMistake[];
60
+ recipes?: ManifestRecipe[];
61
+ }
62
+ export interface ValidationFix {
63
+ kind: string;
64
+ from?: string;
65
+ to?: string;
66
+ }
67
+ export interface ValidationIssue {
68
+ file: string;
69
+ line: number;
70
+ rule: string;
71
+ severity: 'error' | 'warning';
72
+ message: string;
73
+ fix?: ValidationFix;
74
+ }
75
+ export interface UncheckedItem {
76
+ reason: string;
77
+ at: string;
78
+ detail: string;
79
+ }
80
+ export type ValidateScore = 'pass' | 'pass-with-warnings' | 'fail';
81
+ export interface ValidateUsageResult {
82
+ libraryVersion: string;
83
+ source: 'manifest' | 'package-parse';
84
+ manifestPath?: string;
85
+ errors: ValidationIssue[];
86
+ unchecked: UncheckedItem[];
87
+ coverage: number;
88
+ score: ValidateScore;
89
+ }
90
+ export interface ResolveManifestResult {
91
+ manifest: ApiManifest;
92
+ source: 'manifest' | 'package-parse';
93
+ manifestPath: string;
94
+ packageRoot: string;
95
+ }
96
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { ParsedAttr } from '../scan/parseMagicGrid.js';
2
+ import type { ValidationIssue } from '../types.js';
3
+ export declare function checkPropTypeLiteral(file: string, attr: ParsedAttr, errors: ValidationIssue[]): boolean;
4
+ //# sourceMappingURL=propTypeLiteral.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propTypeLiteral.d.ts","sourceRoot":"","sources":["../../src/validate/propTypeLiteral.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAoBlD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,eAAe,EAAE,GACxB,OAAO,CAqCT"}
@@ -0,0 +1,48 @@
1
+ /** 字面量 prop 的枚举/形态校验(v1 · 仅高频误写) */
2
+ const STRING_ENUM_PROPS = {
3
+ rowSelection: ['single', 'multiple'],
4
+ size: ['mini', 'small', 'default', 'large'],
5
+ };
6
+ const NUMERIC_PROPS = new Set([
7
+ 'rowHeight',
8
+ 'rowBuffer',
9
+ 'scrollEndFlushMs',
10
+ 'headerHeight',
11
+ 'floatingFiltersHeight',
12
+ ]);
13
+ function resolvePropName(name) {
14
+ return name.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
15
+ }
16
+ export function checkPropTypeLiteral(file, attr, errors) {
17
+ if (attr.isBinding || attr.literalValue === true) {
18
+ return false;
19
+ }
20
+ const value = typeof attr.literalValue === 'string' ? attr.literalValue.trim() : null;
21
+ if (value === null) {
22
+ return false;
23
+ }
24
+ const propKey = resolvePropName(attr.name);
25
+ const allowed = STRING_ENUM_PROPS[propKey];
26
+ if (allowed && !allowed.includes(value)) {
27
+ errors.push({
28
+ file,
29
+ line: attr.line,
30
+ rule: 'prop-type-literal',
31
+ severity: 'error',
32
+ message: `${attr.name}="${value}" 无效,允许值:${allowed.join(' | ')}`,
33
+ fix: { kind: 'fix-literal', from: value, to: allowed[0] ?? '' },
34
+ });
35
+ return true;
36
+ }
37
+ if (NUMERIC_PROPS.has(propKey) && value !== '' && Number.isNaN(Number(value))) {
38
+ errors.push({
39
+ file,
40
+ line: attr.line,
41
+ rule: 'prop-type-literal',
42
+ severity: 'error',
43
+ message: `${attr.name} 应为数字字面量,收到 "${value}"`,
44
+ });
45
+ return true;
46
+ }
47
+ return false;
48
+ }
@@ -0,0 +1,9 @@
1
+ import type { ResolveManifestResult } from '../resolveManifest.js';
2
+ import type { ValidateUsageResult } from '../types.js';
3
+ interface ValidateOptions {
4
+ cwd?: string;
5
+ paths: string[];
6
+ }
7
+ export declare function validateMagicGridUsage(resolved: ResolveManifestResult, options: ValidateOptions): ValidateUsageResult;
8
+ export {};
9
+ //# sourceMappingURL=validateUsage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateUsage.d.ts","sourceRoot":"","sources":["../../src/validate/validateUsage.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,KAAK,EAGV,mBAAmB,EAEpB,MAAM,aAAa,CAAA;AAWpB,UAAU,eAAe;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,qBAAqB,EAC/B,OAAO,EAAE,eAAe,GACvB,mBAAmB,CAmIrB"}