Skip to content

feat: smart tree truncation and subtree extraction#45

Merged
piotrski merged 14 commits intomainfrom
feat/smart-tree-truncation
Apr 3, 2026
Merged

feat: smart tree truncation and subtree extraction#45
piotrski merged 14 commits intomainfrom
feat/smart-tree-truncation

Conversation

@piotrski
Copy link
Copy Markdown
Collaborator

@piotrski piotrski commented Mar 18, 2026

Summary

Closes #20

Smart tree truncation and subtree extraction for the get tree command, making output practical for large React apps (500-2000+ components).

Tree truncation

  • Host filtering by default: <div>, <span>, etc. are hidden (use --all to show). Keyed hosts and custom elements are always shown.
  • Sibling collapsing: Repeated siblings with the same display name collapse after 3 items with ... +N more ComponentName.
  • Summary footer: N components shown (M total) at the end of output.
  • --max-lines N flag: Hard cap on output lines for context budgets.

Subtree extraction

  • get tree @c5 shows only the subtree rooted at a specific component.
  • Labels re-assigned starting from @c1 within the subtree.
  • Combines with --depth, --all, and --max-lines flags.

Fixes on top of original implementation

  • Validate numeric IDs exist in resolveId (stale/typo'd IDs now return not-found)
  • Enforce --max-lines budget including truncation and summary footer lines
  • Update E2E tests for new { nodes, totalCount } response shape

Test plan

  • All 103 unit tests pass
  • Type checking passes
  • Build succeeds
  • E2E tests pass on CI
  • Manual: get tree on a large app shows truncated output with summary
  • Manual: get tree @c5 shows correct subtree
  • Manual: get tree --all includes host components
  • Manual: get tree --max-lines 20 caps output

Supersedes #36

🤖 Generated with Claude Code

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 18, 2026

🦋 Changeset detected

Latest commit: 753a0bf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-react-devtools Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fa2b1c1ab8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@piotrski piotrski force-pushed the feat/smart-tree-truncation branch from fa2b1c1 to d36e4bc Compare March 18, 2026 00:28
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d36e4bc5db

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1468ea65fc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +161 to +163
if (truncated) {
// Replace last tree line with truncation notice to stay within budget
lines[lines.length - 1] = `... output truncated at ${maxLines} lines`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Guard truncation replacement when no lines were emitted

The truncation path assumes at least one rendered tree line and overwrites lines[lines.length - 1], but lineLimit can be 0 (or negative) when maxLines is very small and a footer is reserved. In that case no tree line is ever pushed, so this write targets index -1 and the truncation notice disappears; e.g. --max-lines 1 currently prints only the summary footer and misrepresents that output was truncated.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed (same fix as the other formatters.ts comment — combined truncation+footer line resolves both issues at once).

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aea5467abe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

piotrski and others added 14 commits April 3, 2026 07:07
Add three complementary strategies to reduce tree output size:

1. Filter host components by default (--all flag to include them)
   - Host components with keys or custom element names are kept
   - Filtering happens at output level, not internal tree structure

2. Collapse repeated siblings with same display name
   - Shows first 3 items, then "... +N more ComponentName"
   - Detects runs of siblings with identical displayName

3. Summary footer showing component count
   - "N components shown (M total)" when filtered
   - "N components" when showing all

Also adds --max-lines N flag as a hard cap on output lines.

Closes #20

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Test host component filtering with noHost option
- Test custom element and keyed host preservation
- Test child promotion when host nodes are skipped
- Test noHost + maxDepth combination
- Test sibling collapsing (repeated display names)
- Test summary footer with totalCount
- Test maxLines truncation
- Test options object variant for formatTree

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document --all, --max-lines flags and smart tree behavior:
- Host filtering enabled by default
- Sibling collapsing for repeated component names
- Summary footer showing component counts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `get tree @c5` syntax to view only the subtree rooted at a specific
component. Labels are re-assigned starting from @c1 within the subtree.
Combines with --depth, --all, and --max-lines flags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
maxLines is a formatting concern, not data. The daemon now returns only
{ nodes, totalCount } in the get-tree response. The CLI passes maxLines
directly to formatTree from the local command flags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The get-tree response changed from an array to { nodes, totalCount }.
Update E2E tests to destructure the new format.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously resolveId always returned numeric IDs without checking if
the node exists, making `get tree 999` return an empty tree instead
of a not-found error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reserve space for both the truncation message and summary footer when
computing the max-lines cutoff, so --max-lines N never emits more
than N lines.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace O(n²) nodes.find() with O(1) nodeMap.get() by building a
Map<number, TreeNode> alongside the existing childrenMap. Also remove
dead isLastChild variable in collapsed-sibling path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Hoist label assignment before the skip/emit branch in getTree walk
- Precompute lineLimit once instead of recalculating reserve on every
  addLine call

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Only reserve truncation line when tree actually exceeds max-lines,
  replacing the last tree line instead of always reserving space
- Return not-found error for stale subtree roots (labels that resolve
  but point to removed nodes)
- Emit filtered children IDs when noHost skips host components, so
  children arrays stay consistent with parentId references

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Never skip the explicitly requested rootId even when noHost filtering
  is active, so `get tree @c5` works for host components
- Guard against index -1 when truncation fires with zero lines emitted
  (e.g. --max-lines 1 with summary footer)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When --max-lines is set and the tree is truncated, the truncation notice
now uses the pre-reserved footer slot (combined line) instead of replacing
the last content line. This shows one additional component line within the
same budget.

Also fixes the --max-lines 1 edge case where the footer was emitted after
the truncation notice, producing 2 lines instead of 1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@piotrski piotrski force-pushed the feat/smart-tree-truncation branch from aea5467 to 753a0bf Compare April 3, 2026 05:07
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 753a0bf836

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +207 to +209
const noHost = flags['all'] !== true;
// Parse optional root: `get tree @c5` or `get tree 5`
const rawRoot = command[2];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Parse --all as a boolean before consuming tree root

With the new optional subtree argument, get tree --all @c5 is parsed incorrectly: the generic arg parser stores flags.all = "@c5", so this branch treats --all as unset (noHost stays true) and rawRoot becomes undefined. That silently drops the requested subtree root and still filters host nodes, which makes a common flag ordering produce the wrong tree without any error.

Useful? React with 👍 / 👎.

@piotrski piotrski merged commit a1bed65 into main Apr 3, 2026
4 checks passed
piotrski added a commit that referenced this pull request Apr 3, 2026
PR #45 changed the get-tree IPC response from a flat array to
{ nodes, totalCount }, but browser.test.ts was not updated to match,
causing the release workflow to fail on every push to main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
piotrski added a commit that referenced this pull request Apr 3, 2026
#49)

PR #45 changed the get-tree IPC response from a flat array to
{ nodes, totalCount }, but browser.test.ts was not updated to match,
causing the release workflow to fail on every push to main.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

Smart tree truncation for large component trees

1 participant