project-graph-mcp 1.0.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.
@@ -0,0 +1,158 @@
1
+ {
2
+ "name": "symbiote-2x",
3
+ "description": "Symbiote.js 2.x component standards",
4
+ "docs": "https://rnd-pro.com/symbiote/",
5
+ "detect": {
6
+ "packageJson": [
7
+ "@symbiotejs/symbiote"
8
+ ],
9
+ "imports": [
10
+ "@symbiotejs/symbiote",
11
+ "from '@symbiotejs/symbiote'"
12
+ ],
13
+ "patterns": [
14
+ "extends Symbiote"
15
+ ]
16
+ },
17
+ "rules": [
18
+ {
19
+ "id": "symbiote-no-host-setattribute",
20
+ "name": "No direct setAttribute on host",
21
+ "description": "Use sub() + setAttribute for reactive host attributes",
22
+ "pattern": "this.setAttribute",
23
+ "patternType": "string",
24
+ "replacement": "sub('prop', v => this.setAttribute(...))",
25
+ "severity": "warning",
26
+ "filePattern": "*.js",
27
+ "exclude": [
28
+ "*.test.js",
29
+ "*.spec.js"
30
+ ],
31
+ "docs": "https://rnd-pro.com/symbiote/2x/examples/attributes/"
32
+ },
33
+ {
34
+ "id": "symbiote-no-host-style",
35
+ "name": "No direct style on host",
36
+ "description": "Use template binding ${{ 'style.x': 'prop' }}",
37
+ "pattern": "this.style.",
38
+ "patternType": "string",
39
+ "replacement": "${{ 'style.x': 'propName' }}",
40
+ "severity": "warning",
41
+ "filePattern": "*.js",
42
+ "docs": "https://rnd-pro.com/symbiote/2x/core/template/"
43
+ },
44
+ {
45
+ "id": "symbiote-no-addeventlistener",
46
+ "name": "No addEventListener on this",
47
+ "description": "Use template binding ${{ onclick: 'handler' }}",
48
+ "pattern": "this.addEventListener",
49
+ "patternType": "string",
50
+ "replacement": "${{ onclick: 'handlerName' }}",
51
+ "severity": "info",
52
+ "filePattern": "*.js",
53
+ "docs": "https://rnd-pro.com/symbiote/2x/core/template/"
54
+ },
55
+ {
56
+ "id": "symbiote-no-createelement",
57
+ "name": "No createElement for lists",
58
+ "description": "Use Itemize API instead of manual DOM creation",
59
+ "pattern": "document.createElement",
60
+ "patternType": "string",
61
+ "replacement": "itemize=\"items\" in template",
62
+ "severity": "warning",
63
+ "filePattern": "*.js",
64
+ "docs": "https://rnd-pro.com/symbiote/2x/features/itemize/"
65
+ },
66
+ {
67
+ "id": "symbiote-no-innerhtml",
68
+ "name": "No innerHTML manipulation",
69
+ "description": "Use Symbiote reactive bindings or Itemize",
70
+ "pattern": ".innerHTML",
71
+ "patternType": "string",
72
+ "replacement": "Itemize API or template bindings",
73
+ "severity": "error",
74
+ "filePattern": "*.js",
75
+ "docs": "https://rnd-pro.com/symbiote/2x/features/itemize/"
76
+ },
77
+ {
78
+ "id": "symbiote-triple-file",
79
+ "name": "Triple-file partitioning",
80
+ "description": "Components should be split into .js, .tpl.js, .css.js",
81
+ "pattern": "template = html`",
82
+ "patternType": "string",
83
+ "replacement": "Import from ComponentName.tpl.js",
84
+ "severity": "info",
85
+ "filePattern": "*.js",
86
+ "exclude": [
87
+ "*.tpl.js"
88
+ ],
89
+ "docs": "https://rnd-pro.com/symbiote/2x/features/styling/"
90
+ },
91
+ {
92
+ "id": "symbiote-itemize-parent-handler",
93
+ "name": "Use ^ prefix for parent handlers in Itemize",
94
+ "description": "Handlers in itemize items need ^ prefix to access parent scope",
95
+ "pattern": "onclick: '(?!\\^)",
96
+ "patternType": "regex",
97
+ "replacement": "onclick: '^handlerName'",
98
+ "severity": "warning",
99
+ "filePattern": "*.tpl.js",
100
+ "contextRequired": "<template>",
101
+ "docs": "https://rnd-pro.com/symbiote/2x/features/itemize/"
102
+ },
103
+ {
104
+ "description": "Property keys nesting not supported (e.g., recentProjects.length). Excludes valid $. child binding and style. property binding.",
105
+ "filePattern": "*.tpl.js",
106
+ "id": "symbiote-no-nested-keys",
107
+ "name": "No nested property keys",
108
+ "pattern": "{{(?![^}]*(?:'\\$\\.|'style\\.))([^}]+\\.[^}]+)}}",
109
+ "patternType": "regex",
110
+ "replacement": "Use flat property like recentProjectsLength",
111
+ "severity": "error"
112
+ },
113
+ {
114
+ "id": "symbiote-esm-only",
115
+ "name": "ESM only - no require()",
116
+ "description": "Use ESM imports, never CommonJS require()",
117
+ "pattern": "require(",
118
+ "patternType": "string",
119
+ "replacement": "import ... from '...'",
120
+ "severity": "error",
121
+ "filePattern": "*.js",
122
+ "docs": "https://rnd-pro.com/symbiote/"
123
+ },
124
+ {
125
+ "id": "symbiote-no-tailwind",
126
+ "name": "No CSS frameworks",
127
+ "description": "Don't use Tailwind or other CSS frameworks",
128
+ "pattern": "tailwind",
129
+ "patternType": "string",
130
+ "replacement": "Use native CSS with design tokens",
131
+ "severity": "error",
132
+ "filePattern": "*.css",
133
+ "docs": "https://rnd-pro.com/symbiote/2x/features/styling/"
134
+ },
135
+ {
136
+ "id": "symbiote-no-bem",
137
+ "name": "No BEM naming",
138
+ "description": "Use attribute selectors over BEM class naming",
139
+ "pattern": "__",
140
+ "patternType": "string",
141
+ "replacement": "[attr] selectors or custom-tag selectors",
142
+ "severity": "warning",
143
+ "filePattern": "*.css.js",
144
+ "docs": "https://rnd-pro.com/symbiote/2x/features/styling/"
145
+ },
146
+ {
147
+ "id": "symbiote-no-double-quotes",
148
+ "name": "Single quotes for strings",
149
+ "description": "Use single quotes, not double quotes",
150
+ "pattern": "= \"",
151
+ "patternType": "string",
152
+ "replacement": "= '...'",
153
+ "severity": "info",
154
+ "filePattern": "*.js",
155
+ "docs": "https://rnd-pro.com/symbiote/"
156
+ }
157
+ ]
158
+ }
@@ -0,0 +1,221 @@
1
+ {
2
+ "name": "symbiote-3x",
3
+ "description": "Symbiote.js 3.x component standards and migration checks",
4
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md",
5
+ "detect": {
6
+ "packageJson": [
7
+ "@symbiotejs/symbiote"
8
+ ],
9
+ "imports": [
10
+ "@symbiotejs/symbiote",
11
+ "from '@symbiotejs/symbiote'"
12
+ ],
13
+ "patterns": [
14
+ "extends Symbiote"
15
+ ]
16
+ },
17
+ "rules": [
18
+ {
19
+ "id": "symbiote-3x-no-applyroute",
20
+ "name": "applyRoute() removed in 3.x",
21
+ "description": "Use AppRouter.navigate() instead of AppRouter.applyRoute()",
22
+ "pattern": "applyRoute(",
23
+ "patternType": "string",
24
+ "replacement": "AppRouter.navigate(route, options)",
25
+ "severity": "error",
26
+ "filePattern": "*.js",
27
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/docs/migration-2x-to-3x.md"
28
+ },
29
+ {
30
+ "id": "symbiote-3x-no-tplprocessors",
31
+ "name": "tplProcessors renamed in 3.x",
32
+ "description": "Use templateProcessors (native Set) instead of tplProcessors",
33
+ "pattern": "tplProcessors",
34
+ "patternType": "string",
35
+ "replacement": "this.templateProcessors.add(processor)",
36
+ "severity": "error",
37
+ "filePattern": "*.js",
38
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/docs/migration-2x-to-3x.md"
39
+ },
40
+ {
41
+ "id": "symbiote-3x-no-addtemplateprocessor",
42
+ "name": "addTemplateProcessor() removed in 3.x",
43
+ "description": "Use this.templateProcessors.add() instead of addTemplateProcessor()",
44
+ "pattern": "addTemplateProcessor(",
45
+ "patternType": "string",
46
+ "replacement": "this.templateProcessors.add(processor)",
47
+ "severity": "error",
48
+ "filePattern": "*.js",
49
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/docs/migration-2x-to-3x.md"
50
+ },
51
+ {
52
+ "id": "symbiote-3x-no-ctxowner-attr",
53
+ "name": "ctx-owner attribute removed in 3.x",
54
+ "description": "ctx-owner HTML attribute is removed. First-registered value always wins for shared context",
55
+ "pattern": "ctx-owner",
56
+ "patternType": "string",
57
+ "replacement": "Remove ctx-owner, first-registered *prop value wins",
58
+ "severity": "warning",
59
+ "filePattern": "*.js",
60
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/docs/migration-2x-to-3x.md"
61
+ },
62
+ {
63
+ "id": "symbiote-3x-no-ctxowner-prop",
64
+ "name": "ctxOwner property removed in 3.x",
65
+ "description": "ctxOwner flag is removed. First-registered value always wins for shared context",
66
+ "pattern": "ctxOwner",
67
+ "patternType": "string",
68
+ "replacement": "Remove ctxOwner, first-registered *prop value wins",
69
+ "severity": "warning",
70
+ "filePattern": "*.js",
71
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/docs/migration-2x-to-3x.md"
72
+ },
73
+ {
74
+ "id": "symbiote-3x-approuter-import",
75
+ "name": "AppRouter removed from main entry point",
76
+ "description": "Import AppRouter from '@symbiotejs/symbiote/core/AppRouter.js' instead of main entry",
77
+ "pattern": "AppRouter.*from\\s+['\"]@symbiotejs/symbiote['\"]",
78
+ "patternType": "regex",
79
+ "replacement": "import { AppRouter } from '@symbiotejs/symbiote/core/AppRouter.js'",
80
+ "severity": "warning",
81
+ "filePattern": "*.js",
82
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/docs/migration-2x-to-3x.md"
83
+ },
84
+ {
85
+ "id": "symbiote-no-innerhtml",
86
+ "name": "No innerHTML manipulation",
87
+ "description": "Use Symbiote reactive bindings or Itemize API instead of innerHTML",
88
+ "pattern": ".innerHTML",
89
+ "patternType": "string",
90
+ "replacement": "Itemize API or template bindings",
91
+ "severity": "error",
92
+ "filePattern": "*.js",
93
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md"
94
+ },
95
+ {
96
+ "id": "symbiote-no-createelement",
97
+ "name": "No createElement for lists",
98
+ "description": "Use Itemize API instead of manual DOM creation",
99
+ "pattern": "document.createElement",
100
+ "patternType": "string",
101
+ "replacement": "itemize='items' in template",
102
+ "severity": "warning",
103
+ "filePattern": "*.js",
104
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md"
105
+ },
106
+ {
107
+ "id": "symbiote-no-host-setattribute",
108
+ "name": "No direct setAttribute on host",
109
+ "description": "Use sub() + setAttribute for reactive host attributes",
110
+ "pattern": "this.setAttribute",
111
+ "patternType": "string",
112
+ "replacement": "sub('prop', v => this.setAttribute(...))",
113
+ "severity": "warning",
114
+ "filePattern": "*.js",
115
+ "exclude": [
116
+ "*.test.js",
117
+ "*.spec.js"
118
+ ],
119
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md"
120
+ },
121
+ {
122
+ "id": "symbiote-no-host-style",
123
+ "name": "No direct style on host",
124
+ "description": "Use template binding ${{ 'style.x': 'prop' }}",
125
+ "pattern": "this.style.",
126
+ "patternType": "string",
127
+ "replacement": "${{ 'style.x': 'propName' }}",
128
+ "severity": "warning",
129
+ "filePattern": "*.js",
130
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md"
131
+ },
132
+ {
133
+ "id": "symbiote-no-addeventlistener",
134
+ "name": "No addEventListener on this",
135
+ "description": "Use template binding ${{ onclick: 'handler' }} or class method fallback",
136
+ "pattern": "this.addEventListener",
137
+ "patternType": "string",
138
+ "replacement": "${{ onclick: 'handlerName' }} or class method",
139
+ "severity": "info",
140
+ "filePattern": "*.js",
141
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md"
142
+ },
143
+ {
144
+ "id": "symbiote-esm-only",
145
+ "name": "ESM only - no require()",
146
+ "description": "Use ESM imports, never CommonJS require()",
147
+ "pattern": "require(",
148
+ "patternType": "string",
149
+ "replacement": "import ... from '...'",
150
+ "severity": "error",
151
+ "filePattern": "*.js",
152
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md"
153
+ },
154
+ {
155
+ "id": "symbiote-no-tailwind",
156
+ "name": "No CSS frameworks",
157
+ "description": "Don't use Tailwind or other CSS frameworks — use native CSS with custom properties",
158
+ "pattern": "tailwind",
159
+ "patternType": "string",
160
+ "replacement": "Use native CSS with design tokens",
161
+ "severity": "error",
162
+ "filePattern": "*.css",
163
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md"
164
+ },
165
+ {
166
+ "id": "symbiote-no-nested-keys",
167
+ "name": "No nested property keys",
168
+ "description": "Property keys nesting not supported (e.g., obj.prop). Excludes valid $. child binding and style. property binding.",
169
+ "pattern": "{{(?![^}]*(?:'\\$\\.|'style\\.))([^}]+\\.[^}]+)}}",
170
+ "patternType": "regex",
171
+ "replacement": "Use flat property like objProp",
172
+ "severity": "error",
173
+ "filePattern": "*.tpl.js"
174
+ },
175
+ {
176
+ "id": "symbiote-static-template",
177
+ "name": "No static template inside class",
178
+ "description": "template is a static property SETTER — assign outside class: MyComp.template = html`...`",
179
+ "pattern": "static template",
180
+ "patternType": "string",
181
+ "replacement": "MyComponent.template = html`...` (outside class body)",
182
+ "severity": "error",
183
+ "filePattern": "*.js",
184
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md"
185
+ },
186
+ {
187
+ "id": "symbiote-no-this-in-template",
188
+ "name": "No this in template strings",
189
+ "description": "Templates are decoupled from component context — don't use ${this.x}",
190
+ "pattern": "${this.",
191
+ "patternType": "string",
192
+ "replacement": "Use {{propName}} or ${{ key: 'propName' }} bindings",
193
+ "severity": "error",
194
+ "filePattern": "*.tpl.js",
195
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md"
196
+ },
197
+ {
198
+ "id": "symbiote-itemize-parent-handler",
199
+ "name": "Use ^ prefix for parent handlers in Itemize",
200
+ "description": "Handlers in itemize items need ^ prefix to access parent scope",
201
+ "pattern": "onclick: '(?!\\^)",
202
+ "patternType": "regex",
203
+ "replacement": "onclick: '^handlerName'",
204
+ "severity": "warning",
205
+ "filePattern": "*.tpl.js",
206
+ "contextRequired": "<template>",
207
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md"
208
+ },
209
+ {
210
+ "id": "symbiote-3x-utils-import",
211
+ "name": "Utils moved to separate entry point in 3.2",
212
+ "description": "UID, create, applyStyles, applyAttributes, setNestedProp, kebabToCamel, reassignDictionary should be imported from '@symbiotejs/symbiote/utils'",
213
+ "pattern": "\\b(UID|setNestedProp|applyStyles|applyAttributes|create|kebabToCamel|reassignDictionary)\\b.*from\\s+['\"]@symbiotejs/symbiote['\"]",
214
+ "patternType": "regex",
215
+ "replacement": "import { ... } from '@symbiotejs/symbiote/utils'",
216
+ "severity": "warning",
217
+ "filePattern": "*.js",
218
+ "docs": "https://github.com/symbiotejs/symbiote.js/blob/main/CHANGELOG.md"
219
+ }
220
+ ]
221
+ }
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "typescript-5",
3
+ "description": "TypeScript 5.x best practices",
4
+ "docs": "https://www.typescriptlang.org/docs/",
5
+ "detect": {
6
+ "packageJson": [
7
+ "typescript"
8
+ ],
9
+ "imports": [],
10
+ "patterns": []
11
+ },
12
+ "rules": [
13
+ {
14
+ "id": "ts-no-any",
15
+ "name": "Avoid any type",
16
+ "description": "Use specific types instead of any",
17
+ "pattern": ": any",
18
+ "patternType": "string",
19
+ "replacement": "Use proper type or unknown",
20
+ "severity": "warning",
21
+ "filePattern": "*.ts",
22
+ "docs": "https://www.typescriptlang.org/docs/handbook/2/types-from-types.html"
23
+ },
24
+ {
25
+ "id": "ts-no-non-null-assertion",
26
+ "name": "Avoid non-null assertion",
27
+ "description": "Use optional chaining or proper null checks",
28
+ "pattern": "!.",
29
+ "patternType": "string",
30
+ "replacement": "?. or proper null check",
31
+ "severity": "warning",
32
+ "filePattern": "*.ts",
33
+ "docs": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#non-null-assertion-operator-postfix-"
34
+ },
35
+ {
36
+ "id": "ts-satisfies-over-as",
37
+ "name": "Use satisfies over as",
38
+ "description": "satisfies preserves type inference while validating",
39
+ "pattern": " as {",
40
+ "patternType": "string",
41
+ "replacement": "satisfies Type",
42
+ "severity": "info",
43
+ "filePattern": "*.ts",
44
+ "docs": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator"
45
+ },
46
+ {
47
+ "id": "ts-const-assertion",
48
+ "name": "Use const assertion for literals",
49
+ "description": "as const makes literals readonly and narrowed",
50
+ "pattern": "readonly ",
51
+ "patternType": "string",
52
+ "replacement": "Consider as const for object literals",
53
+ "severity": "info",
54
+ "filePattern": "*.ts",
55
+ "docs": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types"
56
+ },
57
+ {
58
+ "id": "ts-explicit-return",
59
+ "name": "Add explicit return types",
60
+ "description": "Public functions should have explicit return types",
61
+ "pattern": "export function [a-zA-Z]+\\([^)]*\\) {",
62
+ "patternType": "regex",
63
+ "replacement": "export function name(): ReturnType { }",
64
+ "severity": "info",
65
+ "filePattern": "*.ts",
66
+ "docs": "https://www.typescriptlang.org/docs/handbook/2/functions.html#return-type-annotations"
67
+ }
68
+ ]
69
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "vue-3",
3
+ "description": "Vue 3 Composition API standards",
4
+ "docs": "https://vuejs.org/",
5
+ "detect": {
6
+ "packageJson": [
7
+ "vue"
8
+ ],
9
+ "imports": [
10
+ "from 'vue'",
11
+ "from \"vue\""
12
+ ],
13
+ "patterns": [
14
+ "defineComponent",
15
+ "ref(",
16
+ "reactive("
17
+ ]
18
+ },
19
+ "rules": [
20
+ {
21
+ "id": "vue-no-options-api",
22
+ "name": "Use Composition API",
23
+ "description": "Prefer Composition API over Options API in Vue 3",
24
+ "pattern": "data() {",
25
+ "patternType": "string",
26
+ "replacement": "const state = reactive({ ... })",
27
+ "severity": "info",
28
+ "filePattern": "*.vue",
29
+ "docs": "https://vuejs.org/guide/extras/composition-api-faq.html"
30
+ },
31
+ {
32
+ "id": "vue-no-this-in-setup",
33
+ "name": "No this in setup()",
34
+ "description": "this is undefined in setup(), use refs and reactive objects",
35
+ "pattern": "this\\.",
36
+ "patternType": "regex",
37
+ "replacement": "Use reactive(), ref(), or inject()",
38
+ "severity": "error",
39
+ "filePattern": "*.vue",
40
+ "docs": "https://vuejs.org/api/composition-api-setup.html"
41
+ },
42
+ {
43
+ "id": "vue-no-v-html",
44
+ "name": "Avoid v-html directive",
45
+ "description": "Can lead to XSS vulnerabilities",
46
+ "pattern": "v-html",
47
+ "patternType": "string",
48
+ "replacement": "Use text interpolation or sanitize content",
49
+ "severity": "warning",
50
+ "filePattern": "*.vue",
51
+ "docs": "https://vuejs.org/api/built-in-directives.html#v-html"
52
+ },
53
+ {
54
+ "id": "vue-key-in-v-for",
55
+ "name": "v-for should have :key",
56
+ "description": "Always use :key with v-for for proper DOM patching",
57
+ "pattern": "v-for=\"[^\"]+\"[^>]*(?!:key)",
58
+ "patternType": "regex",
59
+ "replacement": "v-for=\"item in items\" :key=\"item.id\"",
60
+ "severity": "error",
61
+ "filePattern": "*.vue",
62
+ "docs": "https://vuejs.org/guide/essentials/list.html#maintaining-state-with-key"
63
+ },
64
+ {
65
+ "id": "vue-script-setup",
66
+ "name": "Use script setup",
67
+ "description": "Prefer <script setup> for cleaner component syntax",
68
+ "pattern": "<script>",
69
+ "patternType": "string",
70
+ "replacement": "<script setup>",
71
+ "severity": "info",
72
+ "filePattern": "*.vue",
73
+ "exclude": [
74
+ "*.js"
75
+ ],
76
+ "docs": "https://vuejs.org/api/sfc-script-setup.html"
77
+ }
78
+ ]
79
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * CLI Command Handlers Registry
3
+ * Extracted from cli.js to reduce cyclomatic complexity
4
+ */
5
+
6
+ import { getSkeleton, getFocusZone, expand, deps, usages } from './tools.js';
7
+ import { getPendingTests, getTestSummary } from './test-annotations.js';
8
+ import { getFilters } from './filters.js';
9
+ import { getInstructions } from './instructions.js';
10
+ import { getUndocumentedSummary } from './undocumented.js';
11
+ import { getDeadCode } from './dead-code.js';
12
+ import { generateJSDoc } from './jsdoc-generator.js';
13
+ import { getSimilarFunctions } from './similar-functions.js';
14
+ import { getComplexity } from './complexity.js';
15
+ import { getLargeFiles } from './large-files.js';
16
+ import { getOutdatedPatterns } from './outdated-patterns.js';
17
+ import { getFullAnalysis } from './full-analysis.js';
18
+ import { resolvePath } from './workspace.js';
19
+
20
+ /**
21
+ * Parse named argument from args array
22
+ * @param {string[]} args
23
+ * @param {string} name
24
+ * @returns {string|undefined}
25
+ */
26
+ function getArg(args, name) {
27
+ const arg = args.find(a => a.startsWith(`--${name}=`));
28
+ return arg ? arg.split('=')[1] : undefined;
29
+ }
30
+
31
+ /**
32
+ * Get path argument (first non-flag arg), resolved against workspace root
33
+ * @param {string[]} args
34
+ * @returns {string}
35
+ */
36
+ function getPath(args) {
37
+ const raw = args.find(a => !a.startsWith('--')) || '.';
38
+ return resolvePath(raw);
39
+ }
40
+
41
+ /**
42
+ * CLI command handlers registry
43
+ * Each handler returns a result or throws an error
44
+ */
45
+ export const CLI_HANDLERS = {
46
+ skeleton: {
47
+ requiresArg: true,
48
+ argError: 'Path required: skeleton <path>',
49
+ handler: async (args) => getSkeleton(resolvePath(args[0])),
50
+ },
51
+
52
+ expand: {
53
+ requiresArg: true,
54
+ argError: 'Symbol required: expand <symbol>',
55
+ handler: async (args) => expand(args[0]),
56
+ },
57
+
58
+ deps: {
59
+ requiresArg: true,
60
+ argError: 'Symbol required: deps <symbol>',
61
+ handler: async (args) => deps(args[0]),
62
+ },
63
+
64
+ usages: {
65
+ requiresArg: true,
66
+ argError: 'Symbol required: usages <symbol>',
67
+ handler: async (args) => usages(args[0]),
68
+ },
69
+
70
+ pending: {
71
+ handler: async (args) => getPendingTests(getPath(args)),
72
+ },
73
+
74
+ summary: {
75
+ handler: async (args) => getTestSummary(getPath(args)),
76
+ },
77
+
78
+ filters: {
79
+ handler: async () => getFilters(),
80
+ },
81
+
82
+ instructions: {
83
+ rawOutput: true,
84
+ handler: async () => getInstructions(),
85
+ },
86
+
87
+ undocumented: {
88
+ handler: async (args) => {
89
+ const level = getArg(args, 'level') || 'tests';
90
+ return getUndocumentedSummary(getPath(args), level);
91
+ },
92
+ },
93
+
94
+ deadcode: {
95
+ handler: async (args) => getDeadCode(getPath(args)),
96
+ },
97
+
98
+ jsdoc: {
99
+ requiresArg: true,
100
+ argError: 'Usage: jsdoc <file>',
101
+ handler: async (args) => generateJSDoc(resolvePath(args[0])),
102
+ },
103
+
104
+ similar: {
105
+ handler: async (args) => {
106
+ const threshold = parseInt(getArg(args, 'threshold')) || 60;
107
+ return getSimilarFunctions(getPath(args), { threshold });
108
+ },
109
+ },
110
+
111
+ complexity: {
112
+ handler: async (args) => {
113
+ const minComplexity = parseInt(getArg(args, 'min')) || 1;
114
+ const onlyProblematic = args.includes('--problematic');
115
+ return getComplexity(getPath(args), { minComplexity, onlyProblematic });
116
+ },
117
+ },
118
+
119
+ largefiles: {
120
+ handler: async (args) => {
121
+ const onlyProblematic = args.includes('--problematic');
122
+ return getLargeFiles(getPath(args), { onlyProblematic });
123
+ },
124
+ },
125
+
126
+ outdated: {
127
+ handler: async (args) => {
128
+ const codeOnly = args.includes('--code');
129
+ const depsOnly = args.includes('--deps');
130
+ return getOutdatedPatterns(getPath(args), { codeOnly, depsOnly });
131
+ },
132
+ },
133
+
134
+ analyze: {
135
+ handler: async (args) => {
136
+ const includeItems = args.includes('--items');
137
+ return getFullAnalysis(getPath(args), { includeItems });
138
+ },
139
+ },
140
+ };