Skip to content

Wire hierarchical team grouping into the CLI end-to-end - #190

Open
shouze wants to merge 2 commits into
feat/team-hierarchy-pick-teamfrom
feat/team-hierarchy-cli
Open

Wire hierarchical team grouping into the CLI end-to-end#190
shouze wants to merge 2 commits into
feat/team-hierarchy-pick-teamfrom
feat/team-hierarchy-cli

Conversation

@shouze

@shouze shouze commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Wires the hierarchical team-prefix grouping built in #177-#181 into the
production CLI end-to-end, replacing the flat groupByTeamPrefix pipeline.

  • --group-by-team-prefix now accepts a chain grammar: / nests levels
    within one chain (gamme-/squad-), , separates independent chains
    (gamme-/squad-,chapter-). Parsed by the new, pure, fully-tested
    parseTeamPrefixChains (malformed segments are dropped with a warning,
    not silently propagated as empty prefixes).
  • The CLI now always builds the tree via groupByTeamHierarchy, even
    for a single flat prefix — a 1-level chain is behaviorally identical to
    the old groupByTeamPrefix (parity already covered by [1/7] Data model & core hierarchical grouping algorithm #177's tests), so
    this isn't a second code path to maintain.
  • Added --group-by-team-prefix-consolidate to apply
    consolidateTeamHierarchy (mechanism 3 from EPIC: Hierarchical team-prefix grouping (multi-level headings) #125/[2/7] Advanced consolidated rendering #178).
  • --pick-team now resolves through the new resolvePickTeamAssignment:
    a bare label auto-resolves when it's unambiguous anywhere in the tree, or
    an explicit "gamme-client > squad-a + squad-b"=squad-a path when nested
    or ambiguous. This single pure function replaces ~90 lines of inline
    validation in github-code-search.ts.
  • Replay command / non-interactive output / interactive TUI all thread
    consolidateTeamSections and path-qualified pickTeams end to end.

Bug caught before it shipped

While wiring this up, src/tui.ts's pick/re-pick/undo handlers still
branched on sectionPath.length > 1 / pickedFrom.includes(" > ") to
decide between the new tree-aware functions and the old flat
rebuildTeamSections/applyTeamPick/flattenTeamSections. Since the CLI
now always produces sectionPath-tagged groups (never the old flat
sectionLabel marker), a pick on a depth-1 (top-level) section — the
common case — would take the "flat" branch, where rebuildTeamSections
finds no sectionLabel-tagged group at all, applyTeamPick no-ops on an
empty array, and the pick would silently wipe every group from the
screen
. Caught with a manual end-to-end smoke test (mock data through the
full parse → group → pick → consolidate → flatten → output pipeline) before
it could reach a real user. Fixed by simplifying the TUI handlers to always
use the tree-aware functions — the old flat functions remain in group.ts,
fully tested, for any other consumer.

Also fixed (found while polishing --help)

A pre-existing Commander help-formatting bug: any option description
containing a newline immediately followed by whitespace (e.g. an indented
example sub-line) makes Help.preformatted() treat the whole
description as already manually formatted and skip aligning continuation
lines to the option column. This affected --exclude-repositories and
--exclude-extracts too, not just the new options here. Fixed by removing
the leading indentation from example lines (still visually distinguished
via the existing colorDesc dimming) and removed a duplicated
"(default: false)" on --include-archived /
--exclude-template-repositories (Commander already appends it from the
option's default-value argument).

Closes #182

How to test

bun test src/group.test.ts
COLUMNS=100 bun github-code-search.ts help query

New group.test.ts tests cover parseTeamPrefixChains (flat, nested,
multi-chain, whitespace, malformed input) and resolvePickTeamAssignment
(unambiguous bare label, nested bare label, explicit qualified path, all
error paths). Manually smoke-tested the full CLI pipeline with mock data
(chain parsing → hierarchy grouping → nested pick-team → consolidation →
markdown output → replay command round-trip).

Validation

  • bun test (961 pass)
  • bun run lint
  • bun run format:check
  • bun run knip
  • bun run build.ts
  • bunx tsc --noEmit sanity check (zero new errors)
  • Manual end-to-end smoke test with mock data (see above)
  • Manual --help output check for formatting

@github-actions

Copy link
Copy Markdown

Coverage after merging feat/team-hierarchy-cli into feat/team-hierarchy-pick-team will be

96.85%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   aggregate.ts100%100%100%100%
   api-utils.ts93.20%100%93.75%93.13%101–103, 65, 73, 86–87, 91–92
   api.ts94.74%100%100%94.07%340–344, 405, 422, 63–69
   cache.ts94.67%100%100%94.29%139–141, 39
   completions.ts99.42%100%100%99.37%270
   group.ts99.37%100%98.08%99.62%546, 552
   output.ts99.37%100%95.83%99.66%84
   regex.ts99.39%100%100%99.34%329
   render.ts90.75%100%88.24%90.85%173, 197–202, 204–206, 208–209, 230, 423–424, 522–526, 556–563, 565–573, 575–578
   scroll-cooldown.ts100%100%100%100%
   upgrade.ts88.38%100%94.44%87.89%128, 131, 133, 153, 167–168, 188–195, 198–204, 209, 214, 250–253
src/render
   filter-match.ts97.44%100%92.31%100%
   filter.ts100%100%100%100%
   highlight.ts96.63%100%90.40%99.31%284–285
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   mouse.ts100%100%100%100%
   rows.ts99.42%100%100%99.38%239
   selection.ts100%100%100%100%
   summary.ts100%100%100%100%
   team-pick.ts100%100%100%100%
   terminal.ts100%100%100%100%

@shouze
shouze marked this pull request as ready for review August 23, 2026 21:31
Copilot AI lite review requested due to automatic review settings August 23, 2026 21:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Wires hierarchical team grouping, consolidation, and path-based team picking through the CLI and TUI.

Changes:

  • Adds prefix-chain parsing and pick resolution.
  • Integrates hierarchy grouping and consolidation end to end.
  • Updates TUI handling, replay support, tests, and help formatting.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Summary Findings
src/tui.ts Tree-aware pick, re-pick, and undo handling Critical: Picking a combined parent with children can drop those children.
src/group.ts Prefix parsing and pick resolution Moderate: Explicit paths are not validated and can record no-op assignments.
src/group.test.ts Parser and resolver tests No final comments.
github-code-search.ts CLI grouping, consolidation, and pick integration Critical: Consolidation before pick resolution can invalidate labels and paths.
Suppressed comments (3)

github-code-search.ts:406

  • A combined node can legitimately have children when a chain has another level (for example, a gamme-a + gamme-b root subdivided by squad-). applyTeamPickInTree moves only the node's direct groups; if they are empty, this call removes the node and its descendants, dropping those repositories from the output. Picking a valid parent section must move or preserve the entire subtree (or explicitly reject non-leaf combined sections) before applying this for all hierarchy paths.
        sections = applyTeamPickInTree(sections, resolution.path, resolution.chosen);

github-code-search.ts:396

  • This mutates the tree used for every output format, so --format json --group-by-team-prefix-consolidate emits synthetic (including …) labels and loses the original hierarchy in each result's section path. Consolidation is a rendering mode and the JSON contract needs the underlying full tree; retain the uncollapsed tree for JSON and derive a consolidated copy only for the relevant presentation.
      if (opts.groupByTeamPrefixConsolidate) {
        sections = consolidateTeamHierarchy(sections);

github-code-search.ts:200

  • src/completions.ts keeps a static OPTIONS list used to generate all installed shell completions, but this new flag is not added there. Consequently bash/zsh/fish users cannot complete --group-by-team-prefix-consolidate even though Commander accepts it; add the flag to the shared completion metadata and its test.
      "--group-by-team-prefix-consolidate",
      [
        "Collapse unambiguous single-branch nesting chains into one heading",
        'with an "(including ...)" suffix instead of one heading per level.',
        "Only applies with --group-by-team-prefix.",
        "Docs: https://fulll.github.io/github-code-search/usage/team-grouping",
      ].join("\n"),
      false,

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread github-code-search.ts Outdated
Comment on lines +395 to +396
if (opts.groupByTeamPrefixConsolidate) {
sections = consolidateTeamHierarchy(sections);
Comment thread src/group.ts
Comment on lines +809 to +810
if (combinedInput.includes(PATH_SEPARATOR)) {
path = combinedInput.split(PATH_SEPARATOR).map((s) => s.trim());
Comment thread src/tui.ts
groups = flattenTeamSections(updated);
}
const sections = rebuildTeamHierarchy(groups);
const updated = applyTeamPickInTree(sections, teamPickMode.sectionPath, chosen);
@shouze
shouze force-pushed the feat/team-hierarchy-cli branch from dbc3e06 to 12a397d Compare August 23, 2026 21:42
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/team-hierarchy-cli into feat/team-hierarchy-pick-team will be

96.83%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   aggregate.ts100%100%100%100%
   api-utils.ts93.20%100%93.75%93.13%101–103, 65, 73, 86–87, 91–92
   api.ts94.74%100%100%94.07%340–344, 405, 422, 63–69
   cache.ts94.67%100%100%94.29%139–141, 39
   completions.ts99.42%100%100%99.37%270
   group.ts99.23%100%98.11%99.45%546, 552, 631
   output.ts99.37%100%95.83%99.66%84
   regex.ts99.39%100%100%99.34%329
   render.ts90.75%100%88.24%90.85%173, 197–202, 204–206, 208–209, 230, 423–424, 522–526, 556–563, 565–573, 575–578
   scroll-cooldown.ts100%100%100%100%
   upgrade.ts88.38%100%94.44%87.89%128, 131, 133, 153, 167–168, 188–195, 198–204, 209, 214, 250–253
src/render
   filter-match.ts97.44%100%92.31%100%
   filter.ts100%100%100%100%
   highlight.ts96.63%100%90.40%99.31%284–285
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   mouse.ts100%100%100%100%
   rows.ts99.42%100%100%99.38%239
   selection.ts100%100%100%100%
   summary.ts100%100%100%100%
   team-pick.ts100%100%100%100%
   terminal.ts100%100%100%100%

1 similar comment
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/team-hierarchy-cli into feat/team-hierarchy-pick-team will be

96.83%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   aggregate.ts100%100%100%100%
   api-utils.ts93.20%100%93.75%93.13%101–103, 65, 73, 86–87, 91–92
   api.ts94.74%100%100%94.07%340–344, 405, 422, 63–69
   cache.ts94.67%100%100%94.29%139–141, 39
   completions.ts99.42%100%100%99.37%270
   group.ts99.23%100%98.11%99.45%546, 552, 631
   output.ts99.37%100%95.83%99.66%84
   regex.ts99.39%100%100%99.34%329
   render.ts90.75%100%88.24%90.85%173, 197–202, 204–206, 208–209, 230, 423–424, 522–526, 556–563, 565–573, 575–578
   scroll-cooldown.ts100%100%100%100%
   upgrade.ts88.38%100%94.44%87.89%128, 131, 133, 153, 167–168, 188–195, 198–204, 209, 214, 250–253
src/render
   filter-match.ts97.44%100%92.31%100%
   filter.ts100%100%100%100%
   highlight.ts96.63%100%90.40%99.31%284–285
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   mouse.ts100%100%100%100%
   rows.ts99.42%100%100%99.38%239
   selection.ts100%100%100%100%
   summary.ts100%100%100%100%
   team-pick.ts100%100%100%100%
   terminal.ts100%100%100%100%

shouze added a commit that referenced this pull request Aug 23, 2026
…tions

Addresses Copilot review on PR #190:
- Reordered CLI wiring so --pick-team assignments resolve against the
  raw, uncollapsed tree BEFORE --group-by-team-prefix-consolidate runs.
  Consolidating first changes (or erases) a combined section's label/
  path, so pick-team could silently fail to find it or misparse a
  synthetic "(including ...)" label as candidate teams.
- Consolidation is now skipped entirely for --format json (with a
  stderr warning when requested): JSON is a data contract and must
  reflect the real, uncollapsed hierarchy in each result's `section`
  path, not a display-only collapsed view. The replay command and TUI
  now receive the same consolidateApplied flag actually used, instead
  of the raw --group-by-team-prefix-consolidate request.
- resolvePickTeamAssignment now validates an explicit "parent > combined"
  path actually resolves to a node in the tree before accepting it —
  previously a typo'd parent (or a path made stale by an earlier pick)
  was accepted, applyTeamPickInTree silently no-op'd, and the caller
  still recorded the assignment for replay as if it had succeeded.
- Added the missing --group-by-team-prefix-consolidate entry to the
  shared shell-completion metadata (bash/zsh/fish) and its tests.

The applyTeamPickInTree/tui.ts "children dropped on pick" findings in
this review were already fixed in the previous commit on this stack
(feat/team-hierarchy-pick-team) — verified still present here.
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/team-hierarchy-cli into feat/team-hierarchy-pick-team will be

96.83%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   aggregate.ts100%100%100%100%
   api-utils.ts93.20%100%93.75%93.13%101–103, 65, 73, 86–87, 91–92
   api.ts94.74%100%100%94.07%340–344, 405, 422, 63–69
   cache.ts94.67%100%100%94.29%139–141, 39
   completions.ts99.44%100%100%99.39%276
   group.ts99.11%100%98.17%99.29%546, 552, 631, 763
   output.ts99.37%100%95.83%99.66%84
   regex.ts99.39%100%100%99.34%329
   render.ts90.75%100%88.24%90.85%173, 197–202, 204–206, 208–209, 230, 423–424, 522–526, 556–563, 565–573, 575–578
   scroll-cooldown.ts100%100%100%100%
   upgrade.ts88.38%100%94.44%87.89%128, 131, 133, 153, 167–168, 188–195, 198–204, 209, 214, 250–253
src/render
   filter-match.ts97.44%100%92.31%100%
   filter.ts100%100%100%100%
   highlight.ts96.63%100%90.40%99.31%284–285
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   mouse.ts100%100%100%100%
   rows.ts99.42%100%100%99.38%239
   selection.ts100%100%100%100%
   summary.ts100%100%100%100%
   team-pick.ts100%100%100%100%
   terminal.ts100%100%100%100%

shouze added 2 commits August 24, 2026 02:14
- github-code-search.ts: --group-by-team-prefix now parses a chain
  grammar (/ for nesting depth, , for independent chains) via the new
  parseTeamPrefixChains, and always uses groupByTeamHierarchy (a
  1-level chain behaves identically to the old flat groupByTeamPrefix,
  covered by parity tests). Added --group-by-team-prefix-consolidate to
  apply consolidateTeamHierarchy. --pick-team now resolves through the
  new resolvePickTeamAssignment (bare-label auto-resolve when
  unambiguous, or an explicit "parent > combined" path), replacing ~90
  lines of inline validation with pure, tested logic.
- src/group.ts: added parseTeamPrefixChains and resolvePickTeamAssignment
  (pure, fully unit-tested CLI-parsing helpers).
- src/tui.ts: simplified pick/re-pick/undo handlers to always use the
  tree-aware functions (rebuildTeamHierarchy/applyTeamPickInTree/etc.),
  since the CLI now always produces sectionPath-tagged groups — the
  previous sectionPath.length/pickedFrom-based branching to the old flat
  functions was dead code that would have silently wiped all groups for
  a depth-1 (top-level) section pick (rebuildTeamSections finds no
  sectionLabel-tagged group, applyTeamPick no-ops on an empty array).
  Caught via a manual end-to-end smoke test before it could ship.

Fixed along the way: a pre-existing Commander help-formatting bug where
any option description containing a newline followed by whitespace
(e.g. an indented example line) made Help.preformatted() treat the
WHOLE description as manually formatted and skip aligning continuation
lines to the option column — affected --exclude-repositories and
--exclude-extracts too, not just the new options. Also removed a
duplicated "(default: false)" on --include-archived/
--exclude-template-repositories (Commander already appends it).

Closes #182
…tions

Addresses Copilot review on PR #190:
- Reordered CLI wiring so --pick-team assignments resolve against the
  raw, uncollapsed tree BEFORE --group-by-team-prefix-consolidate runs.
  Consolidating first changes (or erases) a combined section's label/
  path, so pick-team could silently fail to find it or misparse a
  synthetic "(including ...)" label as candidate teams.
- Consolidation is now skipped entirely for --format json (with a
  stderr warning when requested): JSON is a data contract and must
  reflect the real, uncollapsed hierarchy in each result's `section`
  path, not a display-only collapsed view. The replay command and TUI
  now receive the same consolidateApplied flag actually used, instead
  of the raw --group-by-team-prefix-consolidate request.
- resolvePickTeamAssignment now validates an explicit "parent > combined"
  path actually resolves to a node in the tree before accepting it —
  previously a typo'd parent (or a path made stale by an earlier pick)
  was accepted, applyTeamPickInTree silently no-op'd, and the caller
  still recorded the assignment for replay as if it had succeeded.
- Added the missing --group-by-team-prefix-consolidate entry to the
  shared shell-completion metadata (bash/zsh/fish) and its tests.

The applyTeamPickInTree/tui.ts "children dropped on pick" findings in
this review were already fixed in the previous commit on this stack
(feat/team-hierarchy-pick-team) — verified still present here.
@shouze
shouze force-pushed the feat/team-hierarchy-cli branch from 45cd3c2 to 69c3bbb Compare August 24, 2026 00:14
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/team-hierarchy-cli into feat/team-hierarchy-pick-team will be

96.85%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   aggregate.ts100%100%100%100%
   api-utils.ts93.20%100%93.75%93.13%101–103, 65, 73, 86–87, 91–92
   api.ts94.74%100%100%94.07%340–344, 405, 422, 63–69
   cache.ts94.67%100%100%94.29%139–141, 39
   completions.ts99.44%100%100%99.39%276
   group.ts99.11%100%98.17%99.29%546, 552, 631, 763
   output.ts99.37%100%95.83%99.66%84
   regex.ts99.39%100%100%99.34%329
   render.ts90.99%100%88.24%91.09%177, 201–206, 208–210, 212–213, 234, 427–428, 528–532, 562–569, 571–579, 581–584
   scroll-cooldown.ts100%100%100%100%
   style.ts100%100%100%100%
   upgrade.ts88.38%100%94.44%87.89%128, 131, 133, 153, 167–168, 188–195, 198–204, 209, 214, 250–253
src/render
   filter-match.ts97.44%100%92.31%100%
   filter.ts100%100%100%100%
   highlight.ts96.63%100%90.40%99.31%284–285
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   mouse.ts100%100%100%100%
   rows.ts99.42%100%100%99.38%239
   selection.ts100%100%100%100%
   summary.ts100%100%100%100%
   team-pick.ts100%100%100%100%
   terminal.ts100%100%100%100%

1 similar comment
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/team-hierarchy-cli into feat/team-hierarchy-pick-team will be

96.85%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   aggregate.ts100%100%100%100%
   api-utils.ts93.20%100%93.75%93.13%101–103, 65, 73, 86–87, 91–92
   api.ts94.74%100%100%94.07%340–344, 405, 422, 63–69
   cache.ts94.67%100%100%94.29%139–141, 39
   completions.ts99.44%100%100%99.39%276
   group.ts99.11%100%98.17%99.29%546, 552, 631, 763
   output.ts99.37%100%95.83%99.66%84
   regex.ts99.39%100%100%99.34%329
   render.ts90.99%100%88.24%91.09%177, 201–206, 208–210, 212–213, 234, 427–428, 528–532, 562–569, 571–579, 581–584
   scroll-cooldown.ts100%100%100%100%
   style.ts100%100%100%100%
   upgrade.ts88.38%100%94.44%87.89%128, 131, 133, 153, 167–168, 188–195, 198–204, 209, 214, 250–253
src/render
   filter-match.ts97.44%100%92.31%100%
   filter.ts100%100%100%100%
   highlight.ts96.63%100%90.40%99.31%284–285
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   mouse.ts100%100%100%100%
   rows.ts99.42%100%100%99.38%239
   selection.ts100%100%100%100%
   summary.ts100%100%100%100%
   team-pick.ts100%100%100%100%
   terminal.ts100%100%100%100%

@shouze shouze self-assigned this Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[6/7] CLI wiring end-to-end

2 participants