ucn 3.7.46 → 3.8.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.
@@ -49,7 +49,17 @@ ucn impact score_trend --exclude=test # Only production callers
49
49
 
50
50
  Replaces: grep for the function name → manually filtering definitions vs calls vs imports → reading context around each match.
51
51
 
52
- ### 3. `trace` — Understand execution flow
52
+ ### 3. `blast` — Transitive blast radius
53
+
54
+ Walks UP the caller chain recursively. Shows the full tree of functions affected transitively if you change something. Like `impact` but recursive — answers "what breaks if I change this, including indirect callers?"
55
+
56
+ ```bash
57
+ ucn blast helper # callers of callers (depth 3)
58
+ ucn blast helper --depth=5 # deeper chain
59
+ ucn blast helper --exclude=test # skip test callers
60
+ ```
61
+
62
+ ### 4. `trace` — Understand execution flow (downward)
53
63
 
54
64
  Draws the call tree downward from any function. Compact by default; setting `--depth=N` shows the full tree to that depth with all children expanded.
55
65
 
@@ -61,7 +71,7 @@ ucn trace generate_report --all # all children at default depth
61
71
 
62
72
  Shows the entire pipeline — what `generate_report` calls, what those functions call, etc. — as an indented tree. No file reading needed. Invaluable for understanding orchestrator functions or entry points.
63
73
 
64
- ### 4. `fn` / `class` — Extract without reading the whole file
74
+ ### 5. `fn` / `class` — Extract without reading the whole file
65
75
 
66
76
  Pull one or more functions out of a large file. Supports comma-separated names for bulk extraction.
67
77
 
@@ -71,7 +81,7 @@ ucn fn parse,format,validate # Extract multiple functions in one call
71
81
  ucn class MarketDataFetcher
72
82
  ```
73
83
 
74
- ### 5. `deadcode` — Find unused code
84
+ ### 6. `deadcode` — Find unused code
75
85
 
76
86
  Lists all functions and classes with zero callers across the project.
77
87
 
@@ -86,6 +96,9 @@ ucn deadcode --exclude=test # Skip test files (most useful)
86
96
  |-----------|---------|-------------|
87
97
  | Quick callers + callees list | `ucn context <name>` | Who calls it and what it calls. Results are numbered for `expand`. Use instead of `about` when you just need the call graph, not source code |
88
98
  | Need function + all its helpers inline | `ucn smart <name>` | Returns function source with every helper it calls expanded below it. Use instead of `about` when you need code, not metadata |
99
+ | Full transitive blast radius | `ucn blast <name> --depth=5` | Callers of callers — the full chain of what breaks if you change something |
100
+ | How execution reaches a function | `ucn reverse-trace <name>` | Walk UP callers to entry points (★ marked). Shows how code flows to this function. Default depth=5 |
101
+ | Which tests to run after a change | `ucn affected-tests <name>` | Blast + test detection: shows test files, coverage %, uncovered functions. Use `--depth=N` to control depth |
89
102
  | What changed and who's affected | `ucn diff-impact --base=main` | Shows changed functions + their callers from git diff |
90
103
  | Checking if a refactor broke signatures | `ucn verify <name>` | Validates all call sites match the function's parameter count |
91
104
  | Understanding a file's role in the project | `ucn imports <file>` | What it depends on |
@@ -97,10 +110,16 @@ ucn deadcode --exclude=test # Skip test files (most useful)
97
110
  | Text search with context | `ucn search term --context=3` | Like grep -C 3, shows surrounding lines |
98
111
  | Regex search (default) | `ucn search '\d+'` | Search supports regex by default (alternation, character classes, etc.) |
99
112
  | Text search filtered | `ucn search term --exclude=test` | Search only in matching files |
113
+ | Structural search (index) | `ucn search --type=function --param=Request` | Query the symbol table, not text. Finds functions by param, return type, decorator, etc. |
114
+ | Find all db.* calls | `ucn search --type=call --receiver=db` | Search call sites by receiver — something grep can't do |
115
+ | Find exported functions | `ucn search --type=function --exported` | Only exported/public symbols |
116
+ | Find unused symbols | `ucn search --type=function --unused` | Mini deadcode: zero callers |
117
+ | Find decorated functions | `ucn search --decorator=Route` | Functions/classes with a specific decorator/annotation |
100
118
  | Finding all usages (not just calls) | `ucn usages <name>` | Groups into: definitions, calls, imports, type references |
101
119
  | Finding sibling/related functions | `ucn related <name>` | Name-based + structural matching (same file, shared deps). Not semantic — best for parse/format pairs |
102
120
  | Preview a rename or param change | `ucn plan <name> --rename-to=new_name` | Shows what would change without doing it |
103
121
  | File-level dependency tree | `ucn graph <file> --depth=1` | Visual import tree. Setting `--depth=N` expands all children. Can be noisy — use depth=1 for large projects. For function-level flow, use `trace` instead |
122
+ | Are there circular dependencies? | `ucn circular-deps` | Detect circular import chains. `--file=<pattern>` filters to cycles involving a file. `--exclude=test` skips test files |
104
123
  | Find which tests cover a function | `ucn tests <name>` | Test files and test function names |
105
124
  | Extract specific lines from a file | `ucn lines --file=<file> --range=10-20` | Pull a line range without reading the whole file |
106
125
  | Find type definitions | `ucn typedef <name>` | Interfaces, enums, structs, traits, type aliases |
@@ -145,12 +164,21 @@ ucn [target] <command> [name] [--flags]
145
164
  | `--detailed` | Show full symbol listing per file in `toc` |
146
165
  | `--top-level` | Show only top-level functions in `toc` (exclude nested/indented) |
147
166
  | `--top=N` | Limit result count (default: 10 for most commands) |
167
+ | `--limit=N` | Limit result count for `find`, `usages`, `search`, `deadcode`, `api`, `toc` |
168
+ | `--max-files=N` | Max files to index (for large projects with 10K+ files) |
148
169
  | `--max-lines=N` | Max source lines for `class` (large classes show summary by default) |
149
170
  | `--case-sensitive` | Case-sensitive text search (default: case-insensitive) |
150
171
  | `--exact` | Exact name match only in `find`/`typedef` (no substring) |
151
172
  | `--include-uncertain` | Include ambiguous/uncertain matches in `context`/`smart`/`about` |
152
173
  | `--include-exported` | Include exported symbols in `deadcode` results |
153
174
  | `--include-decorated` | Include decorated/annotated symbols in `deadcode` results |
175
+ | `--type=<kind>` | Structural search: `function`, `class`, `call`, `method`, `type`. Triggers index query instead of text grep |
176
+ | `--param=<name>` | Structural search: filter by parameter name or type (e.g., `--param=Request`) |
177
+ | `--receiver=<name>` | Structural search: filter calls by receiver (e.g., `--receiver=db` for all db.* calls) |
178
+ | `--returns=<type>` | Structural search: filter by return type (e.g., `--returns=error`) |
179
+ | `--decorator=<name>` | Structural search: filter by decorator/annotation (e.g., `--decorator=Route`) |
180
+ | `--exported` | Structural search: only exported/public symbols |
181
+ | `--unused` | Structural search: only symbols with zero callers |
154
182
 
155
183
  ## Workflow Integration
156
184
 
@@ -162,7 +190,9 @@ ucn trace problematic_function --depth=2 # See what it calls
162
190
 
163
191
  **Before modifying a function:**
164
192
  ```bash
165
- ucn impact the_function # Who will break?
193
+ ucn impact the_function # Who will break? (direct callers)
194
+ ucn blast the_function # Who will break? (full transitive chain)
195
+ ucn affected-tests the_function # Which tests to run after the change?
166
196
  ucn smart the_function # See it + its helpers
167
197
  # ... make changes ...
168
198
  ucn verify the_function # Did all call sites survive?
package/README.md CHANGED
@@ -38,7 +38,7 @@ Supports JS/TS, Python, Go, Rust, Java, and HTML. Runs locally.
38
38
 
39
39
  ┌──────┴──────┐
40
40
  │ UCN Engine │
41
- 28 commands
41
+ commands
42
42
  │ tree-sitter │
43
43
  └─────────────┘
44
44
  ```
@@ -138,7 +138,7 @@ VS Code uses `.vscode/mcp.json`:
138
138
 
139
139
  </details>
140
140
 
141
- All 28 commands ship as a single MCP tool - under 2KB of context.
141
+ All commands ship as a single MCP tool - under 2KB of context.
142
142
 
143
143
  ### Agent Skill (no server needed)
144
144
 
@@ -265,28 +265,31 @@ ucn deadcode --exclude=test # what can be deleted?
265
265
 
266
266
  ---
267
267
 
268
- ## All 28 commands
268
+ ## All commands
269
269
 
270
270
  ```
271
271
  UNDERSTAND MODIFY SAFELY
272
272
  ───────────────────── ─────────────────────
273
273
  about full picture impact all call sites
274
- context callers + callees diff-impact git diff + callers
275
- smart function + helpers verify signature check
276
- trace call tree plan refactor preview
274
+ context callers + callees blast transitive impact
275
+ smart function + helpers diff-impact git diff + callers
276
+ trace call tree verify signature check
277
+ reverse-trace callers → root plan refactor preview
277
278
 
278
279
  FIND & EXTRACT ARCHITECTURE
279
280
  ───────────────────── ─────────────────────
280
281
  find locate definitions imports file dependencies
281
282
  usages all occurrences exporters reverse dependencies
282
283
  fn extract function graph dependency tree
283
- class extract class related sibling functions
284
- toc project overview tests find test coverage
285
- deadcode unused code stacktrace error trace context
286
- search text search api public API surface
287
- example best usage example typedef type definitions
288
- lines extract line range file-exports file's exports
289
- expand drill into context stats project stats
284
+ class extract class circular-deps import cycles
285
+ toc project overview related sibling functions
286
+ deadcode unused code tests find test coverage
287
+ search text search affected-tests tests for changes
288
+ example best usage example stacktrace error trace context
289
+ lines extract line range api public API surface
290
+ expand drill into context typedef type definitions
291
+ file-exports file's exports
292
+ stats project stats
290
293
  ```
291
294
 
292
295
  ---
package/cli/index.js CHANGED
@@ -102,6 +102,16 @@ function parseFlags(tokens) {
102
102
  regex: tokens.includes('--no-regex') ? false : undefined,
103
103
  functions: tokens.includes('--functions'),
104
104
  className: getValueFlag('--class-name'),
105
+ limit: parseInt(getValueFlag('--limit') || '0') || undefined,
106
+ maxFiles: parseInt(getValueFlag('--max-files') || '0') || undefined,
107
+ // Structural search flags
108
+ type: getValueFlag('--type'),
109
+ param: getValueFlag('--param'),
110
+ receiver: getValueFlag('--receiver'),
111
+ returns: getValueFlag('--returns'),
112
+ decorator: getValueFlag('--decorator'),
113
+ exported: tokens.includes('--exported'),
114
+ unused: tokens.includes('--unused'),
105
115
  };
106
116
  }
107
117
 
@@ -126,7 +136,8 @@ const knownFlags = new Set([
126
136
  '--default', '--top', '--no-follow-symlinks',
127
137
  '--base', '--staged', '--stack',
128
138
  '--regex', '--no-regex', '--functions',
129
- '--max-lines', '--class-name'
139
+ '--max-lines', '--class-name', '--limit', '--max-files',
140
+ '--type', '--param', '--receiver', '--returns', '--decorator', '--exported', '--unused'
130
141
  ]);
131
142
 
132
143
  // Handle help flag
@@ -285,7 +296,9 @@ function runFileCommand(filePath, command, arg) {
285
296
 
286
297
  // Require arg for commands that need it
287
298
  const needsArg = { fn: 'fn <name>', class: 'class <name>', find: 'find <name>', usages: 'usages <name>', search: 'search <term>', lines: 'lines <start-end>', typedef: 'typedef <name>' };
288
- if (needsArg[canonical]) {
299
+ // Structural search doesn't require term
300
+ const isStructural = flags.type || flags.param || flags.receiver || flags.returns || flags.decorator || flags.exported || flags.unused;
301
+ if (needsArg[canonical] && !(canonical === 'search' && isStructural)) {
289
302
  requireArg(arg, `Usage: ucn <file> ${needsArg[canonical]}`);
290
303
  }
291
304
 
@@ -340,7 +353,11 @@ function runFileCommand(filePath, command, arg) {
340
353
  printOutput(result, r => output.formatUsagesJson(r, arg), r => output.formatUsages(r, arg));
341
354
  break;
342
355
  case 'search':
343
- printOutput(result, r => output.formatSearchJson(r, arg), r => output.formatSearch(r, arg));
356
+ if (result && result.meta && result.meta.mode === 'structural') {
357
+ printOutput(result, output.formatStructuralSearchJson, output.formatStructuralSearch);
358
+ } else {
359
+ printOutput(result, r => output.formatSearchJson(r, arg), r => output.formatSearch(r, arg));
360
+ }
344
361
  break;
345
362
  case 'typedef':
346
363
  printOutput(result, r => output.formatTypedefJson(r, arg), r => output.formatTypedef(r, arg));
@@ -396,7 +413,7 @@ function runProjectCommand(rootDir, command, arg) {
396
413
  // If cache was loaded but stale, force rebuild to avoid duplicates
397
414
  let needsCacheSave = false;
398
415
  if (!usedCache) {
399
- index.build(null, { quiet: flags.quiet, forceRebuild: cacheWasLoaded, followSymlinks: flags.followSymlinks });
416
+ index.build(null, { quiet: flags.quiet, forceRebuild: cacheWasLoaded, followSymlinks: flags.followSymlinks, maxFiles: flags.maxFiles });
400
417
  needsCacheSave = flags.cache;
401
418
  }
402
419
 
@@ -408,8 +425,9 @@ function runProjectCommand(rootDir, command, arg) {
408
425
  // ── Commands using shared executor ───────────────────────────────
409
426
 
410
427
  case 'toc': {
411
- const { ok, result, error } = execute(index, 'toc', flags);
428
+ const { ok, result, error, note } = execute(index, 'toc', flags);
412
429
  if (!ok) fail(error);
430
+ if (note) console.error(note);
413
431
  printOutput(result, output.formatTocJson, r => output.formatToc(r, {
414
432
  detailedHint: 'Add --detailed to list all functions, or "ucn . about <name>" for full details on a symbol',
415
433
  uncertainHint: 'use --include-uncertain to include all'
@@ -429,8 +447,9 @@ function runProjectCommand(rootDir, command, arg) {
429
447
  }
430
448
 
431
449
  case 'usages': {
432
- const { ok, result, error } = execute(index, 'usages', { name: arg, ...flags });
450
+ const { ok, result, error, note } = execute(index, 'usages', { name: arg, ...flags });
433
451
  if (!ok) fail(error);
452
+ if (note) console.error(note);
434
453
  printOutput(result,
435
454
  r => output.formatUsagesJson(r, arg),
436
455
  r => output.formatUsages(r, arg)
@@ -533,6 +552,13 @@ function runProjectCommand(rootDir, command, arg) {
533
552
  break;
534
553
  }
535
554
 
555
+ case 'blast': {
556
+ const { ok, result, error } = execute(index, 'blast', { name: arg, ...flags });
557
+ if (!ok) fail(error);
558
+ printOutput(result, output.formatBlastJson, output.formatBlast);
559
+ break;
560
+ }
561
+
536
562
  case 'plan': {
537
563
  const { ok, result, error } = execute(index, 'plan', { name: arg, ...flags });
538
564
  if (!ok) fail(error);
@@ -547,6 +573,13 @@ function runProjectCommand(rootDir, command, arg) {
547
573
  break;
548
574
  }
549
575
 
576
+ case 'reverseTrace': {
577
+ const { ok, result, error } = execute(index, 'reverseTrace', { name: arg, ...flags });
578
+ if (!ok) fail(error);
579
+ printOutput(result, output.formatReverseTraceJson, output.formatReverseTrace);
580
+ break;
581
+ }
582
+
550
583
  case 'stacktrace': {
551
584
  const { ok, result, error } = execute(index, 'stacktrace', { stack: arg });
552
585
  if (!ok) fail(error);
@@ -642,6 +675,13 @@ function runProjectCommand(rootDir, command, arg) {
642
675
  break;
643
676
  }
644
677
 
678
+ case 'circularDeps': {
679
+ const { ok, result, error } = execute(index, 'circularDeps', { file: flags.file, exclude: flags.exclude });
680
+ if (!ok) fail(error);
681
+ printOutput(result, output.formatCircularDepsJson, output.formatCircularDeps);
682
+ break;
683
+ }
684
+
645
685
  // ── Remaining commands ──────────────────────────────────────────
646
686
 
647
687
  case 'typedef': {
@@ -664,9 +704,17 @@ function runProjectCommand(rootDir, command, arg) {
664
704
  break;
665
705
  }
666
706
 
707
+ case 'affectedTests': {
708
+ const { ok, result, error } = execute(index, 'affectedTests', { name: arg, ...flags });
709
+ if (!ok) fail(error);
710
+ printOutput(result, output.formatAffectedTestsJson, output.formatAffectedTests);
711
+ break;
712
+ }
713
+
667
714
  case 'api': {
668
- const { ok, result, error } = execute(index, 'api', { file: arg });
715
+ const { ok, result, error, note } = execute(index, 'api', { file: arg || flags.file, limit: flags.limit });
669
716
  if (!ok) fail(error);
717
+ if (note) console.error(note);
670
718
  printOutput(result,
671
719
  r => output.formatApiJson(r, arg),
672
720
  r => output.formatApi(r, arg)
@@ -675,18 +723,23 @@ function runProjectCommand(rootDir, command, arg) {
675
723
  }
676
724
 
677
725
  case 'search': {
678
- const { ok, result, error } = execute(index, 'search', { term: arg, ...flags });
726
+ const { ok, result, error, structural } = execute(index, 'search', { term: arg, ...flags });
679
727
  if (!ok) fail(error);
680
- printOutput(result,
681
- r => output.formatSearchJson(r, arg),
682
- r => output.formatSearch(r, arg)
683
- );
728
+ if (structural) {
729
+ printOutput(result, output.formatStructuralSearchJson, output.formatStructuralSearch);
730
+ } else {
731
+ printOutput(result,
732
+ r => output.formatSearchJson(r, arg),
733
+ r => output.formatSearch(r, arg)
734
+ );
735
+ }
684
736
  break;
685
737
  }
686
738
 
687
739
  case 'deadcode': {
688
- const { ok, result, error } = execute(index, 'deadcode', { ...flags, in: flags.in || subdirScope });
740
+ const { ok, result, error, note } = execute(index, 'deadcode', { ...flags, in: flags.in || subdirScope });
689
741
  if (!ok) fail(error);
742
+ if (note) console.error(note);
690
743
  printOutput(result,
691
744
  output.formatDeadcodeJson,
692
745
  r => output.formatDeadcode(r, {
@@ -987,7 +1040,9 @@ UNDERSTAND CODE (UCN's strength - semantic analysis)
987
1040
  context <name> Who calls this + what it calls (numbered for expand)
988
1041
  smart <name> Function + all dependencies inline
989
1042
  impact <name> What breaks if changed (call sites grouped by file)
1043
+ blast <name> Transitive blast radius (callers of callers, --depth=N)
990
1044
  trace <name> Call tree visualization (--depth=N expands all children)
1045
+ reverse-trace <name> Upward call chain to entry points (--depth=N, default 5)
991
1046
  related <name> Find similar functions (same file, shared deps)
992
1047
  example <name> Best usage example with context
993
1048
 
@@ -998,7 +1053,9 @@ FIND CODE
998
1053
  usages <name> All usages grouped: definitions, calls, imports, references
999
1054
  toc Table of contents (compact; --detailed lists all symbols)
1000
1055
  search <term> Text search (regex default, --context=N, --exclude=, --in=)
1056
+ Structural: --type=function|class|call --param= --returns= --decorator= --exported --unused
1001
1057
  tests <name> Find test files for a function
1058
+ affected-tests <n> Tests affected by a change (blast + test detection, --depth=N)
1002
1059
 
1003
1060
  ═══════════════════════════════════════════════════════════════════════════════
1004
1061
  EXTRACT CODE
@@ -1015,6 +1072,7 @@ FILE DEPENDENCIES
1015
1072
  exporters <file> Who imports this file
1016
1073
  file-exports <file> What does file export
1017
1074
  graph <file> Full dependency tree (--depth=N, --direction=imports|importers|both)
1075
+ circular-deps Detect circular import chains (--file=, --exclude=)
1018
1076
 
1019
1077
  ═══════════════════════════════════════════════════════════════════════════════
1020
1078
  REFACTORING HELPERS
@@ -1040,6 +1098,8 @@ Common Flags:
1040
1098
  --direction=X Graph direction: imports, importers, or both (default: both)
1041
1099
  --all Expand truncated sections (about, trace, graph, related)
1042
1100
  --top=N Limit results (find, deadcode)
1101
+ --limit=N Limit result count (find, usages, search, deadcode, api, toc)
1102
+ --max-files=N Max files to index (large projects)
1043
1103
  --context=N Lines of context around matches
1044
1104
  --json Machine-readable output
1045
1105
  --code-only Filter out comments and strings
@@ -1120,18 +1180,23 @@ Commands:
1120
1180
  expand <N> Show code for item N from context
1121
1181
  smart <name> Function + dependencies
1122
1182
  impact <name> What breaks if changed
1183
+ blast <name> Transitive blast radius (--depth=N)
1123
1184
  trace <name> Call tree (--depth=N)
1185
+ reverse-trace <name> Upward to entry points (--depth=N)
1124
1186
  example <name> Best usage example
1125
1187
  related <name> Sibling functions
1126
1188
  fn <name>[,n2,...] Extract function(s) (--file=)
1127
1189
  class <name> Extract class code (--file=)
1128
1190
  lines <range> Extract lines (--file= required)
1129
1191
  graph <file> File dependency tree (--direction=, --depth=)
1192
+ circular-deps Circular import chains (--file=, --exclude=)
1130
1193
  file-exports <file> File's exported symbols
1131
1194
  imports <file> What file imports
1132
1195
  exporters <file> Who imports file
1133
1196
  tests <name> Find tests (--calls-only)
1197
+ affected-tests <n> Tests affected by a change (--depth=N)
1134
1198
  search <term> Text search (--context=N, --exclude=, --in=)
1199
+ Structural: --type= --param= --returns= --decorator= --exported --unused
1135
1200
  typedef <name> Find type definitions
1136
1201
  deadcode Find unused functions/classes
1137
1202
  verify <name> Check call sites match signature
@@ -1341,6 +1406,13 @@ function executeInteractiveCommand(index, command, arg, iflags = {}, cache = nul
1341
1406
  break;
1342
1407
  }
1343
1408
 
1409
+ case 'blast': {
1410
+ const { ok, result, error } = execute(index, 'blast', { name: arg, ...iflags });
1411
+ if (!ok) { console.log(error); return; }
1412
+ console.log(output.formatBlast(result));
1413
+ break;
1414
+ }
1415
+
1344
1416
  case 'trace': {
1345
1417
  const { ok, result, error } = execute(index, 'trace', { name: arg, ...iflags });
1346
1418
  if (!ok) { console.log(error); return; }
@@ -1348,6 +1420,13 @@ function executeInteractiveCommand(index, command, arg, iflags = {}, cache = nul
1348
1420
  break;
1349
1421
  }
1350
1422
 
1423
+ case 'reverseTrace': {
1424
+ const { ok, result, error } = execute(index, 'reverseTrace', { name: arg, ...iflags });
1425
+ if (!ok) { console.log(error); return; }
1426
+ console.log(output.formatReverseTrace(result));
1427
+ break;
1428
+ }
1429
+
1351
1430
  case 'graph': {
1352
1431
  const { ok, result, error } = execute(index, 'graph', { file: arg, ...iflags });
1353
1432
  if (!ok) { console.log(error); return; }
@@ -1356,6 +1435,13 @@ function executeInteractiveCommand(index, command, arg, iflags = {}, cache = nul
1356
1435
  break;
1357
1436
  }
1358
1437
 
1438
+ case 'circularDeps': {
1439
+ const { ok, result, error } = execute(index, 'circularDeps', { file: iflags.file, exclude: iflags.exclude });
1440
+ if (!ok) { console.log(error); return; }
1441
+ console.log(output.formatCircularDeps(result));
1442
+ break;
1443
+ }
1444
+
1359
1445
  case 'fileExports': {
1360
1446
  const { ok, result, error } = execute(index, 'fileExports', { file: arg });
1361
1447
  if (!ok) { console.log(error); return; }
@@ -1384,10 +1470,21 @@ function executeInteractiveCommand(index, command, arg, iflags = {}, cache = nul
1384
1470
  break;
1385
1471
  }
1386
1472
 
1473
+ case 'affectedTests': {
1474
+ const { ok, result, error } = execute(index, 'affectedTests', { name: arg, ...iflags });
1475
+ if (!ok) { console.log(error); return; }
1476
+ console.log(output.formatAffectedTests(result));
1477
+ break;
1478
+ }
1479
+
1387
1480
  case 'search': {
1388
- const { ok, result, error } = execute(index, 'search', { term: arg, ...iflags });
1481
+ const { ok, result, error, structural } = execute(index, 'search', { term: arg, ...iflags });
1389
1482
  if (!ok) { console.log(error); return; }
1390
- console.log(output.formatSearch(result, arg));
1483
+ if (structural) {
1484
+ console.log(output.formatStructuralSearch(result));
1485
+ } else {
1486
+ console.log(output.formatSearch(result, arg));
1487
+ }
1391
1488
  break;
1392
1489
  }
1393
1490