Prerelease Six - api graph and unification
We match every http call to the endpoint it hits now, draw the graph at module grain!
✨ Opus 5 Summary
The api graph, a picture you can read at module grain, and a folder of repos read as one
The api graph
- every endpoint a repo serves matched to every http call site that reaches it, drawn in red as the one edge that crosses a repo, so a folder of repos shows its frontend reaching into its backend
- endpoints come off routers, their prefixes and file based routes across sixteen frameworks; call sites off fetch, axios, requests, httpx, retrofit, okhttp, reqwest and the repo's own wrappers
- OpenAPI, Swagger and
.protoread as endpoints, Bruno, Postman and.httpcollections as call sites - a spec also says which hosts the fleet answers on, which is how an internal call is told from a call to OpenAI
desprawl apiprints both sides
A picture you can read
- module grain draws modules as boxes, each carrying its name, size and shape, and it is what the graph opens on
- a line is something you can open: hovering names both ends and what it carries, clicking lists the imports, calls and requests on it and every path along it. Reachable on 22% of the picture rather than 2%
- laid out to be read, not to be tall: each repo gets a lane sized from its own content, the lanes pack into rows, and nothing that calls out is drawn above or right of something that answers
- three tabs: Overview, Graph, Tasks. History, Files, Modules and Execution became panels, and old links still land where they meant to
- panels drag, reorder and hide per tab, saved between runs
A folder of repos, read as a set
- the picker in the header ticks which repos the page is about, and every panel follows it
- picking filters what was already read rather than reading again: unticking one of five went from twelve seconds to three
- a folder claims no name, version or licence of its own
Things you can build on
import { analyze, build, calls, cycles, fold, knowledge } from "desprawl", with types. One entry point, everything else internal- every
--jsonis an envelope,{ desprawl, kind, repo, made, data }, and--limitand the error shape are the same across all views - panel search finds any panel on any tab by what it is called and what it holds
- tables window past 60 rows, with frozen column widths and the total pinned to the floor of the scroll
- exports moved into one dialog, and controls sit on the panel they change
- the repo is laid out in folders now, every declaration over 300 lines and every file over 700 split behind it, so desprawl reports no size, shape or cycle work on itself
Fixes worth naming
- python bodies ended at their first line, so two thirds of the call graph was attributed to a file's top level: on a django backend that took call coverage from 72% to 92%
- C and C++ saw only definitions in the first column, missing every method in a class and every prototype in a header: an arduino firmware went from 22% to 68%
- a repo past thirty thousand files ran out of heap building its call graph. The linux kernel now reads as 1.4m declarations and 3.9m calls, and a windowed table's first paint on 150k declarations went from 30 seconds to under one
- every tailwind class list read as repeated text: 238 of 287 findings on one frontend were className attributes
--anondid not anonymise. It left the per-identity list beside the blanked one, and only ran when a page was being written- a folder of repos answered with the first repo's numbers for the timeline, commits, tests and size, and returned a 500 for dependencies and history
- an
export { a, b }swallowed the next import, a jvm wildcard import named nothing, and PHP single quotes read as character literals - a crate was called
npm:tokio, and a small repo in a folder collapsed to one module - the exporters lied about what a table held:
1.10shipped as1.1, invalid TOML for backslashes and newlines, tabs shifting every column after them, and no guard on a cell a spreadsheet would run