ucn 3.7.18 → 3.7.19

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,166 @@
1
+ /**
2
+ * Canonical Command Registry — single source of truth for all UCN surfaces.
3
+ *
4
+ * Every command and parameter is defined here. CLI, MCP, and interactive mode
5
+ * derive their command lists, enum values, and param normalization from this.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ // ============================================================================
11
+ // CANONICAL COMMANDS
12
+ // ============================================================================
13
+
14
+ // All 28 commands using camelCase canonical IDs.
15
+ // Order: understanding, finding, extracting, file-deps, refactoring, other.
16
+ const CANONICAL_COMMANDS = [
17
+ // Understanding code
18
+ 'about', 'context', 'impact', 'smart', 'trace', 'example', 'related',
19
+ // Finding code
20
+ 'find', 'usages', 'toc', 'search', 'tests', 'deadcode',
21
+ // Extracting code
22
+ 'fn', 'class', 'lines', 'expand',
23
+ // File dependencies
24
+ 'imports', 'exporters', 'fileExports', 'graph',
25
+ // Refactoring
26
+ 'verify', 'plan', 'diffImpact',
27
+ // Other
28
+ 'typedef', 'stacktrace', 'api', 'stats',
29
+ ];
30
+
31
+ // ============================================================================
32
+ // COMMAND ALIASES (surface-specific → canonical)
33
+ // ============================================================================
34
+
35
+ // CLI uses hyphenated multi-word names plus legacy aliases.
36
+ const CLI_ALIASES = {
37
+ 'file-exports': 'fileExports',
38
+ 'what-exports': 'fileExports',
39
+ 'diff-impact': 'diffImpact',
40
+ 'what-imports': 'imports',
41
+ 'who-imports': 'exporters',
42
+ 'stack': 'stacktrace',
43
+ };
44
+
45
+ // MCP uses snake_case for multi-word names.
46
+ const MCP_ALIASES = {
47
+ 'file_exports': 'fileExports',
48
+ 'diff_impact': 'diffImpact',
49
+ };
50
+
51
+ // ============================================================================
52
+ // PARAM NORMALIZATION (snake_case → camelCase)
53
+ // ============================================================================
54
+
55
+ const PARAM_MAP = {
56
+ project_dir: 'projectDir',
57
+ include_tests: 'includeTests',
58
+ include_methods: 'includeMethods',
59
+ include_uncertain: 'includeUncertain',
60
+ with_types: 'withTypes',
61
+ code_only: 'codeOnly',
62
+ case_sensitive: 'caseSensitive',
63
+ include_exported: 'includeExported',
64
+ include_decorated: 'includeDecorated',
65
+ calls_only: 'callsOnly',
66
+ max_lines: 'maxLines',
67
+ add_param: 'addParam',
68
+ remove_param: 'removeParam',
69
+ rename_to: 'renameTo',
70
+ default_value: 'defaultValue',
71
+ top_level: 'topLevel',
72
+ };
73
+
74
+ // ============================================================================
75
+ // HELPERS
76
+ // ============================================================================
77
+
78
+ /**
79
+ * Resolve a surface-specific command name to its canonical ID.
80
+ *
81
+ * @param {string} name - Command name as used by the surface (e.g. 'diff-impact', 'diff_impact')
82
+ * @param {'cli'|'mcp'} [surface='cli'] - Which surface's aliases to check first
83
+ * @returns {string|null} Canonical command ID, or null if unknown
84
+ */
85
+ function resolveCommand(name, surface) {
86
+ if (CANONICAL_COMMANDS.includes(name)) return name;
87
+ if (surface === 'mcp') {
88
+ return MCP_ALIASES[name] || CLI_ALIASES[name] || null;
89
+ }
90
+ return CLI_ALIASES[name] || null;
91
+ }
92
+
93
+ /**
94
+ * Convert snake_case params to camelCase.
95
+ * Passes through params not in PARAM_MAP unchanged.
96
+ */
97
+ function normalizeParams(params) {
98
+ const result = {};
99
+ for (const [key, value] of Object.entries(params)) {
100
+ result[PARAM_MAP[key] || key] = value;
101
+ }
102
+ return result;
103
+ }
104
+
105
+ // ============================================================================
106
+ // SURFACE-SPECIFIC GENERATORS
107
+ // ============================================================================
108
+
109
+ /**
110
+ * Generate the CLI COMMANDS set (canonical names + all CLI aliases).
111
+ * Includes hyphenated forms and legacy aliases.
112
+ */
113
+ function getCliCommandSet() {
114
+ const set = new Set();
115
+
116
+ for (const cmd of CANONICAL_COMMANDS) {
117
+ // Add hyphenated form for CLI (single-word commands stay as-is)
118
+ const hyphenated = cmd.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
119
+ set.add(hyphenated);
120
+ }
121
+
122
+ // Add legacy aliases
123
+ for (const alias of Object.keys(CLI_ALIASES)) {
124
+ set.add(alias);
125
+ }
126
+
127
+ return set;
128
+ }
129
+
130
+ /**
131
+ * Generate the MCP z.enum array.
132
+ * Uses snake_case for multi-word commands.
133
+ */
134
+ function getMcpCommandEnum() {
135
+ return CANONICAL_COMMANDS.map(cmd => {
136
+ // Convert camelCase → snake_case for multi-word
137
+ return cmd.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Convert a canonical command ID to its MCP surface name.
143
+ */
144
+ function toMcpName(canonical) {
145
+ return canonical.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
146
+ }
147
+
148
+ /**
149
+ * Convert a canonical command ID to its CLI surface name (hyphenated).
150
+ */
151
+ function toCliName(canonical) {
152
+ return canonical.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
153
+ }
154
+
155
+ module.exports = {
156
+ CANONICAL_COMMANDS,
157
+ CLI_ALIASES,
158
+ MCP_ALIASES,
159
+ PARAM_MAP,
160
+ resolveCommand,
161
+ normalizeParams,
162
+ getCliCommandSet,
163
+ getMcpCommandEnum,
164
+ toMcpName,
165
+ toCliName,
166
+ };
@@ -412,8 +412,8 @@ function isMatchInCommentOrString(rootNode, line, lineContent, term) {
412
412
  * @returns {Array<{line: number, content: string, column: number}>}
413
413
  */
414
414
  function findMatchesWithASTFilter(content, term, parser, options = {}) {
415
- const { PARSE_OPTIONS } = require('./index');
416
- const tree = parser.parse(content, undefined, PARSE_OPTIONS);
415
+ const { safeParse } = require('./index');
416
+ const tree = safeParse(parser, content);
417
417
  const lines = content.split('\n');
418
418
  const matches = [];
419
419