ucn 3.1.8 → 3.3.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.
Potentially problematic release.
This version of ucn might be problematic. Click here for more details.
- package/.claude/skills/ucn/SKILL.md +113 -48
- package/README.md +159 -29
- package/cli/index.js +147 -137
- package/core/discovery.js +1 -2
- package/core/imports.js +157 -331
- package/core/output.js +129 -147
- package/core/project.js +484 -220
- package/languages/go.js +21 -10
- package/languages/java.js +25 -9
- package/languages/javascript.js +56 -37
- package/languages/python.js +39 -10
- package/languages/rust.js +36 -8
- package/package.json +1 -1
- package/test/parser.test.js +967 -7
- package/test/reliability-test-prompt.md +58 -0
package/cli/index.js
CHANGED
|
@@ -46,6 +46,10 @@ const flags = {
|
|
|
46
46
|
includeTests: args.includes('--include-tests'),
|
|
47
47
|
// Deadcode options
|
|
48
48
|
includeExported: args.includes('--include-exported'),
|
|
49
|
+
// Uncertain matches (off by default)
|
|
50
|
+
includeUncertain: args.includes('--include-uncertain'),
|
|
51
|
+
// Detailed listing (e.g. toc with all symbols)
|
|
52
|
+
detailed: args.includes('--detailed'),
|
|
49
53
|
// Output depth
|
|
50
54
|
depth: args.find(a => a.startsWith('--depth='))?.split('=')[1] || null,
|
|
51
55
|
// Inline expansion for callees
|
|
@@ -78,7 +82,7 @@ const knownFlags = new Set([
|
|
|
78
82
|
'--json', '--verbose', '--no-quiet', '--quiet',
|
|
79
83
|
'--code-only', '--with-types', '--top-level', '--exact',
|
|
80
84
|
'--no-cache', '--clear-cache', '--include-tests',
|
|
81
|
-
'--include-exported', '--expand', '--interactive', '-i', '--all', '--include-methods',
|
|
85
|
+
'--include-exported', '--expand', '--interactive', '-i', '--all', '--include-methods', '--include-uncertain', '--detailed',
|
|
82
86
|
'--file', '--context', '--exclude', '--not', '--in',
|
|
83
87
|
'--depth', '--add-param', '--remove-param', '--rename-to',
|
|
84
88
|
'--default', '--top', '--no-follow-symlinks'
|
|
@@ -529,57 +533,11 @@ function usagesInFile(code, lines, name, filePath, result) {
|
|
|
529
533
|
return;
|
|
530
534
|
}
|
|
531
535
|
} catch (e) {
|
|
532
|
-
//
|
|
536
|
+
// AST parsing failed — usages will be empty, only definitions shown
|
|
533
537
|
}
|
|
534
538
|
}
|
|
535
539
|
|
|
536
|
-
//
|
|
537
|
-
const regex = new RegExp('\\b' + escapeRegExp(name) + '\\b');
|
|
538
|
-
lines.forEach((line, idx) => {
|
|
539
|
-
const lineNum = idx + 1;
|
|
540
|
-
|
|
541
|
-
// Skip definition lines
|
|
542
|
-
if (defs.some(d => d.startLine === lineNum)) {
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
if (regex.test(line)) {
|
|
547
|
-
if (flags.codeOnly && isCommentOrString(line)) {
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
// Skip if the match is inside a string literal
|
|
552
|
-
if (isInsideString(line, name)) {
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
const usageType = classifyUsage(line, name);
|
|
557
|
-
const usage = {
|
|
558
|
-
file: filePath,
|
|
559
|
-
relativePath: filePath,
|
|
560
|
-
line: lineNum,
|
|
561
|
-
content: line,
|
|
562
|
-
usageType,
|
|
563
|
-
isDefinition: false
|
|
564
|
-
};
|
|
565
|
-
|
|
566
|
-
// Add context
|
|
567
|
-
if (flags.context > 0) {
|
|
568
|
-
const before = [];
|
|
569
|
-
const after = [];
|
|
570
|
-
for (let i = 1; i <= flags.context; i++) {
|
|
571
|
-
if (idx - i >= 0) before.unshift(lines[idx - i]);
|
|
572
|
-
if (idx + i < lines.length) after.push(lines[idx + i]);
|
|
573
|
-
}
|
|
574
|
-
usage.before = before;
|
|
575
|
-
usage.after = after;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
usages.push(usage);
|
|
579
|
-
}
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
// Add definitions to result
|
|
540
|
+
// Output definitions + any usages found via AST
|
|
583
541
|
const allUsages = [
|
|
584
542
|
...defs.map(d => ({
|
|
585
543
|
...d,
|
|
@@ -698,7 +656,7 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
698
656
|
|
|
699
657
|
switch (command) {
|
|
700
658
|
case 'toc': {
|
|
701
|
-
const toc = index.getToc();
|
|
659
|
+
const toc = index.getToc({ detailed: flags.detailed, topLevel: flags.topLevel });
|
|
702
660
|
printOutput(toc, output.formatTocJson, printProjectToc);
|
|
703
661
|
break;
|
|
704
662
|
}
|
|
@@ -745,7 +703,15 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
745
703
|
|
|
746
704
|
case 'context': {
|
|
747
705
|
requireArg(arg, 'Usage: ucn . context <name>');
|
|
748
|
-
const ctx = index.context(arg, {
|
|
706
|
+
const ctx = index.context(arg, {
|
|
707
|
+
includeMethods: flags.includeMethods,
|
|
708
|
+
includeUncertain: flags.includeUncertain,
|
|
709
|
+
file: flags.file
|
|
710
|
+
});
|
|
711
|
+
if (!ctx) {
|
|
712
|
+
console.log(`Symbol "${arg}" not found.`);
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
749
715
|
printOutput(ctx,
|
|
750
716
|
output.formatContextJson,
|
|
751
717
|
r => { printContext(r, { expand: flags.expand, root: index.root }); }
|
|
@@ -776,7 +742,11 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
776
742
|
|
|
777
743
|
case 'smart': {
|
|
778
744
|
requireArg(arg, 'Usage: ucn . smart <name>');
|
|
779
|
-
const smart = index.smart(arg, {
|
|
745
|
+
const smart = index.smart(arg, {
|
|
746
|
+
withTypes: flags.withTypes,
|
|
747
|
+
includeMethods: flags.includeMethods,
|
|
748
|
+
includeUncertain: flags.includeUncertain
|
|
749
|
+
});
|
|
780
750
|
if (smart) {
|
|
781
751
|
printOutput(smart, output.formatSmartJson, printSmart);
|
|
782
752
|
} else {
|
|
@@ -952,6 +922,9 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
952
922
|
const exported = item.isExported ? ' [exported]' : '';
|
|
953
923
|
console.log(` ${output.lineRange(item.startLine, item.endLine)} ${item.name} (${item.type})${exported}`);
|
|
954
924
|
}
|
|
925
|
+
if (!flags.includeExported) {
|
|
926
|
+
console.log(`\nExported symbols excluded by default. Add --include-exported to include them.`);
|
|
927
|
+
}
|
|
955
928
|
}
|
|
956
929
|
);
|
|
957
930
|
}
|
|
@@ -1023,26 +996,27 @@ function extractFunctionFromProject(index, name) {
|
|
|
1023
996
|
return;
|
|
1024
997
|
}
|
|
1025
998
|
|
|
999
|
+
let match;
|
|
1026
1000
|
if (matches.length > 1 && !flags.file) {
|
|
1027
|
-
//
|
|
1028
|
-
|
|
1029
|
-
|
|
1001
|
+
// Auto-select best match using same scoring as resolveSymbol
|
|
1002
|
+
match = pickBestDefinition(matches);
|
|
1003
|
+
console.error(`Note: Found ${matches.length} definitions for "${name}". Using ${match.relativePath}:${match.startLine}. Use --file to disambiguate.`);
|
|
1004
|
+
} else {
|
|
1005
|
+
match = matches[0];
|
|
1030
1006
|
}
|
|
1031
1007
|
|
|
1032
|
-
|
|
1008
|
+
// Extract code directly using symbol index location (works for class methods and overloads)
|
|
1033
1009
|
const code = fs.readFileSync(match.file, 'utf-8');
|
|
1034
|
-
const
|
|
1035
|
-
const
|
|
1010
|
+
const lines = code.split('\n');
|
|
1011
|
+
const fnCode = lines.slice(match.startLine - 1, match.endLine).join('\n');
|
|
1036
1012
|
|
|
1037
|
-
if (
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
console.log(fnCode);
|
|
1045
|
-
}
|
|
1013
|
+
if (flags.json) {
|
|
1014
|
+
console.log(output.formatFunctionJson(match, fnCode));
|
|
1015
|
+
} else {
|
|
1016
|
+
console.log(`${match.relativePath}:${match.startLine}`);
|
|
1017
|
+
console.log(`${output.lineRange(match.startLine, match.endLine)} ${output.formatFunctionSignature(match)}`);
|
|
1018
|
+
console.log('─'.repeat(60));
|
|
1019
|
+
console.log(fnCode);
|
|
1046
1020
|
}
|
|
1047
1021
|
}
|
|
1048
1022
|
|
|
@@ -1056,13 +1030,15 @@ function extractClassFromProject(index, name) {
|
|
|
1056
1030
|
return;
|
|
1057
1031
|
}
|
|
1058
1032
|
|
|
1033
|
+
let match;
|
|
1059
1034
|
if (matches.length > 1 && !flags.file) {
|
|
1060
|
-
//
|
|
1061
|
-
|
|
1062
|
-
|
|
1035
|
+
// Auto-select best match using same scoring as resolveSymbol
|
|
1036
|
+
match = pickBestDefinition(matches);
|
|
1037
|
+
console.error(`Note: Found ${matches.length} definitions for "${name}". Using ${match.relativePath}:${match.startLine}. Use --file to disambiguate.`);
|
|
1038
|
+
} else {
|
|
1039
|
+
match = matches[0];
|
|
1063
1040
|
}
|
|
1064
1041
|
|
|
1065
|
-
const match = matches[0];
|
|
1066
1042
|
const code = fs.readFileSync(match.file, 'utf-8');
|
|
1067
1043
|
const language = detectLanguage(match.file);
|
|
1068
1044
|
const { cls, code: clsCode } = extractClass(code, language, match.name);
|
|
@@ -1080,29 +1056,61 @@ function extractClassFromProject(index, name) {
|
|
|
1080
1056
|
}
|
|
1081
1057
|
|
|
1082
1058
|
function printProjectToc(toc) {
|
|
1083
|
-
|
|
1084
|
-
console.log(`
|
|
1085
|
-
console.log(
|
|
1086
|
-
|
|
1087
|
-
for (const file of toc.byFile) {
|
|
1088
|
-
// Filter for top-level only if flag is set
|
|
1089
|
-
let functions = file.functions;
|
|
1090
|
-
if (flags.topLevel) {
|
|
1091
|
-
functions = functions.filter(fn => !fn.isNested && (!fn.indent || fn.indent === 0));
|
|
1092
|
-
}
|
|
1059
|
+
const t = toc.totals;
|
|
1060
|
+
console.log(`PROJECT: ${t.files} files, ${t.lines} lines`);
|
|
1061
|
+
console.log(` ${t.functions} functions, ${t.classes} classes, ${t.state} state objects`);
|
|
1093
1062
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1063
|
+
// Show meta warnings only when there's something noteworthy
|
|
1064
|
+
const meta = toc.meta || {};
|
|
1065
|
+
const warnings = [];
|
|
1066
|
+
if (meta.dynamicImports) warnings.push(`${meta.dynamicImports} dynamic import(s)`);
|
|
1067
|
+
if (meta.uncertain) warnings.push(`${meta.uncertain} uncertain reference(s)`);
|
|
1068
|
+
if (warnings.length) {
|
|
1069
|
+
const hint = meta.uncertain ? ' — use --include-uncertain to include all' : '';
|
|
1070
|
+
console.log(` Note: ${warnings.join(', ')}${hint}`);
|
|
1071
|
+
}
|
|
1097
1072
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1073
|
+
// Hints
|
|
1074
|
+
if (toc.summary) {
|
|
1075
|
+
if (toc.summary.topFunctionFiles?.length) {
|
|
1076
|
+
const hint = toc.summary.topFunctionFiles.map(f => `${f.file} (${f.functions})`).join(', ');
|
|
1077
|
+
console.log(` Most functions: ${hint}`);
|
|
1100
1078
|
}
|
|
1079
|
+
if (toc.summary.topLineFiles?.length) {
|
|
1080
|
+
const hint = toc.summary.topLineFiles.map(f => `${f.file} (${f.lines})`).join(', ');
|
|
1081
|
+
console.log(` Largest files: ${hint}`);
|
|
1082
|
+
}
|
|
1083
|
+
if (toc.summary.entryFiles?.length) {
|
|
1084
|
+
console.log(` Entry points: ${toc.summary.entryFiles.join(', ')}`);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1101
1087
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1088
|
+
console.log('═'.repeat(60));
|
|
1089
|
+
const hasDetail = toc.files.some(f => f.symbols);
|
|
1090
|
+
for (const file of toc.files) {
|
|
1091
|
+
const parts = [`${file.lines} lines`];
|
|
1092
|
+
if (file.functions) parts.push(`${file.functions} fn`);
|
|
1093
|
+
if (file.classes) parts.push(`${file.classes} cls`);
|
|
1094
|
+
if (file.state) parts.push(`${file.state} state`);
|
|
1095
|
+
|
|
1096
|
+
if (hasDetail) {
|
|
1097
|
+
console.log(`\n${file.file} (${parts.join(', ')})`);
|
|
1098
|
+
if (file.symbols) {
|
|
1099
|
+
for (const fn of file.symbols.functions) {
|
|
1100
|
+
console.log(` ${output.lineRange(fn.startLine, fn.endLine)} ${output.formatFunctionSignature(fn)}`);
|
|
1101
|
+
}
|
|
1102
|
+
for (const cls of file.symbols.classes) {
|
|
1103
|
+
console.log(` ${output.lineRange(cls.startLine, cls.endLine)} ${output.formatClassSignature(cls)}`);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
} else {
|
|
1107
|
+
console.log(` ${file.file} — ${parts.join(', ')}`);
|
|
1104
1108
|
}
|
|
1105
1109
|
}
|
|
1110
|
+
|
|
1111
|
+
if (!hasDetail) {
|
|
1112
|
+
console.log(`\nAdd --detailed to list all functions, or "ucn . about <name>" for full details on a symbol`);
|
|
1113
|
+
}
|
|
1106
1114
|
}
|
|
1107
1115
|
|
|
1108
1116
|
function printSymbols(symbols, query, options = {}) {
|
|
@@ -1552,7 +1560,7 @@ function printBestExample(index, name) {
|
|
|
1552
1560
|
|
|
1553
1561
|
function printContext(ctx, options = {}) {
|
|
1554
1562
|
// Handle struct/interface types differently
|
|
1555
|
-
if (ctx.type && ['struct', 'interface', 'type'].includes(ctx.type)) {
|
|
1563
|
+
if (ctx.type && ['class', 'struct', 'interface', 'type'].includes(ctx.type)) {
|
|
1556
1564
|
console.log(`Context for ${ctx.type} ${ctx.name}:`);
|
|
1557
1565
|
console.log('═'.repeat(60));
|
|
1558
1566
|
|
|
@@ -1614,6 +1622,17 @@ function printContext(ctx, options = {}) {
|
|
|
1614
1622
|
console.log(`Context for ${ctx.function}:`);
|
|
1615
1623
|
console.log('═'.repeat(60));
|
|
1616
1624
|
|
|
1625
|
+
// Show meta note when results may be incomplete
|
|
1626
|
+
if (ctx.meta) {
|
|
1627
|
+
const notes = [];
|
|
1628
|
+
if (ctx.meta.dynamicImports) notes.push(`${ctx.meta.dynamicImports} dynamic import(s)`);
|
|
1629
|
+
if (ctx.meta.uncertain) notes.push(`${ctx.meta.uncertain} uncertain call(s) skipped`);
|
|
1630
|
+
if (notes.length) {
|
|
1631
|
+
const hint = ctx.meta.uncertain ? ' — use --include-uncertain to include all' : '';
|
|
1632
|
+
console.log(` Note: ${notes.join(', ')}${hint}`);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1617
1636
|
// Display warnings if any
|
|
1618
1637
|
if (ctx.warnings && ctx.warnings.length > 0) {
|
|
1619
1638
|
console.log('\n⚠️ WARNINGS:');
|
|
@@ -1763,6 +1782,18 @@ function printExpandedItem(item, root) {
|
|
|
1763
1782
|
function printSmart(smart) {
|
|
1764
1783
|
console.log(`${smart.target.name} (${smart.target.file}:${smart.target.startLine})`);
|
|
1765
1784
|
console.log('═'.repeat(60));
|
|
1785
|
+
|
|
1786
|
+
// Show meta note when results may be incomplete
|
|
1787
|
+
if (smart.meta) {
|
|
1788
|
+
const notes = [];
|
|
1789
|
+
if (smart.meta.dynamicImports) notes.push(`${smart.meta.dynamicImports} dynamic import(s)`);
|
|
1790
|
+
if (smart.meta.uncertain) notes.push(`${smart.meta.uncertain} uncertain call(s) skipped`);
|
|
1791
|
+
if (notes.length) {
|
|
1792
|
+
const hint = smart.meta.uncertain ? ' — use --include-uncertain to include all' : '';
|
|
1793
|
+
console.log(` Note: ${notes.join(', ')}${hint}`);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1766
1797
|
console.log(smart.target.code);
|
|
1767
1798
|
|
|
1768
1799
|
if (smart.dependencies.length > 0) {
|
|
@@ -2122,6 +2153,30 @@ function printLines(lines, range) {
|
|
|
2122
2153
|
}
|
|
2123
2154
|
}
|
|
2124
2155
|
|
|
2156
|
+
/**
|
|
2157
|
+
* Pick the best definition from multiple matches using same scoring as resolveSymbol.
|
|
2158
|
+
* Prefers lib/src/core over test/examples/vendor directories.
|
|
2159
|
+
*/
|
|
2160
|
+
function pickBestDefinition(matches) {
|
|
2161
|
+
const typeOrder = new Set(['class', 'struct', 'interface', 'type', 'impl']);
|
|
2162
|
+
const scored = matches.map(m => {
|
|
2163
|
+
let score = 0;
|
|
2164
|
+
const rp = m.relativePath || '';
|
|
2165
|
+
// Prefer class/struct/interface types (+1000) - same as resolveSymbol
|
|
2166
|
+
if (typeOrder.has(m.type)) score += 1000;
|
|
2167
|
+
if (isTestFile(rp, detectLanguage(m.file))) score -= 500;
|
|
2168
|
+
if (/^(examples?|docs?|vendor|third[_-]?party|benchmarks?|samples?)\//i.test(rp)) score -= 300;
|
|
2169
|
+
if (/^(lib|src|core|internal|pkg|crates)\//i.test(rp)) score += 200;
|
|
2170
|
+
// Tiebreaker: prefer larger function bodies (more important/complex)
|
|
2171
|
+
if (m.startLine && m.endLine) {
|
|
2172
|
+
score += Math.min(m.endLine - m.startLine, 100);
|
|
2173
|
+
}
|
|
2174
|
+
return { match: m, score };
|
|
2175
|
+
});
|
|
2176
|
+
scored.sort((a, b) => b.score - a.score);
|
|
2177
|
+
return scored[0].match;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2125
2180
|
function suggestSimilar(query, names) {
|
|
2126
2181
|
const lower = query.toLowerCase();
|
|
2127
2182
|
const similar = names.filter(n => n.toLowerCase().includes(lower));
|
|
@@ -2137,27 +2192,6 @@ function escapeRegExp(text) {
|
|
|
2137
2192
|
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
2138
2193
|
}
|
|
2139
2194
|
|
|
2140
|
-
function classifyUsage(line, name) {
|
|
2141
|
-
// Check if it's an import first
|
|
2142
|
-
if (/^\s*(import|from|require|use)\b/.test(line)) {
|
|
2143
|
-
return 'import';
|
|
2144
|
-
}
|
|
2145
|
-
// Check if it's a function call (but not a method call)
|
|
2146
|
-
if (new RegExp('\\b' + escapeRegExp(name) + '\\s*\\(').test(line)) {
|
|
2147
|
-
// Exclude method calls (obj.name, this.name, JSON.name, etc.)
|
|
2148
|
-
if (!isMethodCall(line, name)) {
|
|
2149
|
-
return 'call';
|
|
2150
|
-
}
|
|
2151
|
-
}
|
|
2152
|
-
return 'reference';
|
|
2153
|
-
}
|
|
2154
|
-
|
|
2155
|
-
function isMethodCall(line, name) {
|
|
2156
|
-
// Check if there's a dot or ] immediately before the name
|
|
2157
|
-
const methodPattern = new RegExp('[.\\]]\\s*' + escapeRegExp(name) + '\\s*\\(');
|
|
2158
|
-
return methodPattern.test(line);
|
|
2159
|
-
}
|
|
2160
|
-
|
|
2161
2195
|
function isCommentOrString(line) {
|
|
2162
2196
|
const trimmed = line.trim();
|
|
2163
2197
|
return trimmed.startsWith('//') ||
|
|
@@ -2166,31 +2200,6 @@ function isCommentOrString(line) {
|
|
|
2166
2200
|
trimmed.startsWith('/*');
|
|
2167
2201
|
}
|
|
2168
2202
|
|
|
2169
|
-
function isInsideString(line, name) {
|
|
2170
|
-
// Simple heuristic: check if name appears inside quotes
|
|
2171
|
-
// Find all string regions in the line
|
|
2172
|
-
const stringRegex = /(['"`])(?:(?!\1|\\).|\\.)*\1/g;
|
|
2173
|
-
let match;
|
|
2174
|
-
|
|
2175
|
-
while ((match = stringRegex.exec(line)) !== null) {
|
|
2176
|
-
const stringContent = match[0];
|
|
2177
|
-
const stringStart = match.index;
|
|
2178
|
-
const stringEnd = stringStart + stringContent.length;
|
|
2179
|
-
|
|
2180
|
-
// Find where the name appears in the line
|
|
2181
|
-
const nameRegex = new RegExp('\\b' + escapeRegExp(name) + '\\b', 'g');
|
|
2182
|
-
let nameMatch;
|
|
2183
|
-
while ((nameMatch = nameRegex.exec(line)) !== null) {
|
|
2184
|
-
const nameStart = nameMatch.index;
|
|
2185
|
-
// Check if this name occurrence is inside the string
|
|
2186
|
-
if (nameStart > stringStart && nameStart < stringEnd) {
|
|
2187
|
-
return true;
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
}
|
|
2191
|
-
return false;
|
|
2192
|
-
}
|
|
2193
|
-
|
|
2194
2203
|
function printUsage() {
|
|
2195
2204
|
console.log(`UCN - Universal Code Navigator
|
|
2196
2205
|
|
|
@@ -2201,6 +2210,7 @@ Usage:
|
|
|
2201
2210
|
ucn <file> [command] [args] Single file mode
|
|
2202
2211
|
ucn <dir> [command] [args] Project mode (specific directory)
|
|
2203
2212
|
ucn "pattern" [command] [args] Glob pattern mode
|
|
2213
|
+
(Default output is text; add --json for machine-readable JSON)
|
|
2204
2214
|
|
|
2205
2215
|
═══════════════════════════════════════════════════════════════════════════════
|
|
2206
2216
|
UNDERSTAND CODE (UCN's strength - semantic analysis)
|
|
@@ -2413,7 +2423,7 @@ function executeInteractiveCommand(index, command, arg) {
|
|
|
2413
2423
|
console.log('Usage: context <name>');
|
|
2414
2424
|
return;
|
|
2415
2425
|
}
|
|
2416
|
-
const ctx = index.context(arg);
|
|
2426
|
+
const ctx = index.context(arg, { includeUncertain: flags.includeUncertain });
|
|
2417
2427
|
printContext(ctx, { expand: flags.expand, root: index.root });
|
|
2418
2428
|
break;
|
|
2419
2429
|
}
|
|
@@ -2423,7 +2433,7 @@ function executeInteractiveCommand(index, command, arg) {
|
|
|
2423
2433
|
console.log('Usage: smart <name>');
|
|
2424
2434
|
return;
|
|
2425
2435
|
}
|
|
2426
|
-
const smart = index.smart(arg, {});
|
|
2436
|
+
const smart = index.smart(arg, { includeUncertain: flags.includeUncertain });
|
|
2427
2437
|
if (smart) {
|
|
2428
2438
|
printSmart(smart);
|
|
2429
2439
|
} else {
|