Implement a trace CLI - alloy-trace#368
Conversation
…ysis New CLI tool for querying Alloy debug trace SQLite databases. Provides commands for inspecting effects, refs, components, symbols, scopes, output files, and aggregate statistics. Commands: effect <list|show|chain|hotspots|ancestry|subtree> ref <list|show|chain|hotspots|fanout|ownership> component <list|show|tree|stats> symbol <list|show> scope <list|show> file <list|show> stats errors query <sql> Features: - Filter by source file, output file, component, name, type - JSON output mode for scripting - Pagination with --limit - Reactive chain analysis (effect→ref→effect chains) - Hotspot detection (most active effects/refs) - Component tree visualization - Per-component overhead statistics - Raw SQL query support Includes input validation, cycle detection in ref chains, and graceful error handling for missing database files.
103 tests across 5 test files covering: - component list/show/tree/stats with filters, json, limits - effect list/show/chain/hotspots/ancestry/subtree - ref list/show/chain/hotspots/fanout/ownership with cycle detection - stats, errors, file, query, symbol, scope commands - utility functions: requireId, shortPath, CTE helpers, pagination
- Add comprehensive README with usage, examples, and schema docs - Add files field to limit published package to dist/ - Add engines constraint (node >= 22.5.0 for node:sqlite)
Add shared formatComponentStack() in types.ts that renders entries as:
at ComponentName (file.tsx:10:5)
Uses shortPath to trim /packages/ prefix. Used by errors command.
Both now use shared formatComponentStack() which renders as:
at ComponentName (short/path.tsx:line:col)
file search now searches the full output file content instead of individual text node values. This finds text that spans multiple render tree nodes (e.g. 'interface Foo' where 'interface' and 'Foo' are separate text nodes). Maps matches back to text nodes by token-based lookup and shows component stack from the most specific matching node.
Match full search string first, then fall back to longest token. Avoids flooding output with every node matching common words like 'interface'.
Search file content for the exact search string. Find the deepest text node containing the search text (or its longest word as fallback). Show only the component stack, no noisy text node lists.
Rewrote file search to use the same approach as the devtools: collect text nodes in DFS tree order (not seq order), diff against file content with diff-match-patch, and map file offsets back to text nodes through equal segments. This fixes two bugs: 1. Cross-node text search (e.g. 'interface ChatMessageAudioUrl') now correctly maps to the declaration's text node, not a reference. 2. All matches now show component stacks, including type references that were previously unmapped due to seq vs output order mismatch. Added diff-match-patch as a dependency and two new tests for DFS ordering and ambiguous text node resolution.
- formatComponentStack now shows render node IDs (e.g. 'at Declaration alloy-framework#42') - File search: removed 'Found N matches' header, 'Match N:' labels, and indentation. Shows 3 lines of context with blank line separator. - Updated seed data and tests to include renderNodeId in component stacks. - Added test for 3-line context and renderNodeId formatting.
Stack traces now hide library/framework frames by default, matching the devtools filtering approach: frames are external if they have no source location or their source is inside node_modules. - Added --all-frames flag to show all stack frames - When frames are hidden, shows hint: '... N framework frames hidden (use --all-frames to show)' - shortPath now converts absolute paths to relative paths from cwd instead of stripping /packages/ prefix - Updated isExternalFrame to use /node_modules/ check (matches devtools)
- Stack traces now use bold for component names, dim for node IDs, and cyan for file locations - Sourceless frames are no longer hidden by default (fixes missing ModelDeclaration and other user components without source annotations) - Only frames with source paths containing /node_modules/ are hidden - Strip ANSI codes in test capture helper for clean assertions
…on re-render - Babel plugin emits import.meta.url instead of hardcoded absolute paths so component source locations resolve to the installed location at runtime - Source maps resolve .js paths back to original .tsx sources when --enable-source-maps is active - Extract shared source-map utilities into debug/source-map.ts, used by both effect source capture and component source resolution - Fix source info loss on For/memo re-render: nodeKinds now stores source alongside kind/name, and recordSubtreeAdded/recordCachedSubtreeChildren preserve it on INSERT OR REPLACE
|
All changed packages have been documented.
Show changes
|
This PR implements a CLI tool to help explore a trace file. Its primary purpose is to enable LLMs to help diagnose what went wrong when something fails. It exposes most of the information found in the devtools UI.