On this page
#Changelog
#0.6.0
The documentation joins the unified site at https://smmh.dev/dirstat/, and the project describes itself consistently in its README, package documentation and manifest.
#Features
- Documentation joins the unified site at https://smmh.dev/dirstat/, and the project describes itself consistently. The README, the docs landing page, the Go package comment and the project manifest now carry one definition of what dirstat is, and the docs site's internal cross-links resolve.
#Fixes
- Correct version reporting. Released binaries reported a fallback version instead of the released one, because the linker's
-Xtarget named a symbol that did not exist.
#0.5.0
New --formats canonical mode: merges alias formats (mjs/js, h/c, hpp/cpp) and names extensionless scripts by their shebang interpreter.
Context
Downstream aggregation over many projects wants per-language totals, not per-spelling totals: mjs and js are one language, h belongs with c, and an extensionless script with #!/usr/bin/env -S uv run python is Python, not text/plain. The default stays raw, so existing JSON consumers see byte-identical output; canonical is opt-in via --formats or the config key.
#Features
- Canonical format names. New
--formats canonical(defaultraw) merges alias formats into one group --mjs/cjsintojs,hintoc,hppintocpp,text/x-pythonintopy-- and names an extensionless script by its shebang interpreter, so a file starting with#!/usr/bin/env -S uv run pythoncounts underpyinstead oftext/plain. Also settable as theformatskey in a--configfile;rawoutput is unchanged.
#0.4.0
The strictcli v0.33.0 declaration regime: declared presence on every flag and argument, and a helped record per closed-set value.
Context
strictcli v0.33.0 makes presence a declaration rather than an inference and replaces bare choice values with records. dirstat's one command is read_only, so the release's other headline rule -- no framework-picked value on a command that writes -- reaches nothing here and every defaulted flag keeps its default.
Two declarations changed shape: --stats replaces Default(nil), the value-shaped spelling of optionality the framework now refuses, with Optional(), and the positional argument drops the removed ArgRequired(bool) form for ArgDefault alone. The eight closed-set flags declare one record per value with its own help, so --help and the generated flag table describe what each value does.
The scan payload is unchanged field for field, which is what the regenerated golden documents show: the only diff in them is the framework envelope's own interface_version and its new writes member.
#Breaking
- **Breaking: machine output is now the strictcli envelope, entered with
--json.** The--output table|jsonflag is gone;dirstat scan --jsonwrites exactly one document to stdout — the framework envelope, whosepayloadmember is the scan document. The document itself is unchanged except that it no longer restatesdirstat_version: the envelope carries it asapp_version. The command declares the payload's JSON Schema, so a deviating document fails the run instead of reaching a consumer. - **The machine envelope moves to
interface_version2 and gains awritesmember, and--dump-schemawrites schema version 2.** The scan payload is unchanged, field for field. A consumer that readspayloadis unaffected; one that pinsinterface_versionsees 2, andwritesis always null here becausescanwrites nothing. In the dumped schema every flag and argument entry carries itspresence, values publish a JSON Schema fragment undervalue_schema, and each choices entry carries its own help.
#Features
- **
--helpdescribes every closed-set value, and states each flag's presence.**--method,--ignored,--hidden,--type,--sort-order,--show,--singletonsand--stylenow render as a block with one line per value and what it does, replacing the one-line[choices: a, b]form, and every flag and the positional argument ends its line with exactly one of[required],[optional]or[default: <value>].
#0.3.0
Text/binary classification is correct again: unknown extensions are content-sniffed, empty files count as text, MIME format names stay readable, plus 17 new text extensions and a documentation site
Context
Scans of mixed trees were silently wrong. Hybrid mode treated any extension missing from the built-in text list as a binary verdict, so GDScript, Godot scenes and resources, go.mod/go.sum and text lockfiles reported no lines of code at all and were tabulated as binary; a zero-byte file was counted as binary for the same structural reason. Both defects are fixed at the classifier: a map miss now falls through to a content sniff (the extension still names the group, the content decides the class), and a zero-byte file is text under every method. The extension list also gained 17 entries so the common cases never pay for a sniff -- lock is deliberately left out, because it is TOML text for some tools and binary for others and must be judged per file.
The third fix is presentational but cost the same trust: two distinct application/* groups both rendered as applicat.. in a squeezed Format column, so the top of a large scan was unreadable without --output json. MIME names now truncate from the left, keeping the subtype.
This release also carries the previously unreleased documentation work: the Embedded Data page, generated tables of text extensions and default excludes, a schema-driven CLI reference, and a complete API reference.
#Features
- Effect classification. Every command now declares its strictcli effect (
dirstat scanisread_only), and the framework-provided--dry-run,--quietand--verboseflags are available on every invocation. - 17 new text extensions. Godot's text formats (
gd,gdshader,tscn,tres,godot,uid), Go'smod/sum, the shader languages (glsl,hlsl,wgsl,frag,vert) andastro/svx/prisma/odinare recognized as text without a content sniff. - Documentation site. A new Embedded Data page explains text/binary classification and lists every built-in text extension and default exclude as generated tables, the CLI reference is built straight from the command schema, and the specification's scan-config section is spelled out in full.
#Fixes
- Correct text/binary classification. A file whose extension is missing from the built-in text list is now content-sniffed instead of being assumed binary, and a zero-byte file counts as text. Formats like GDScript, Godot scenes,
go.mod/go.sumand text lockfiles stop reporting zero lines of code and no longer land in the Binary Files table. - Readable MIME format names in tables. When the Format column is squeezed, MIME-type group names keep their subtype (
..n/x-sharedlib) instead of collapsing to an indistinguishableapplicat.., so two differentapplication/*groups can be told apart without switching to--output json. - API reference. The generated API Reference index is no longer empty and every package now carries a doc comment, so each internal package has a real reference page.
#0.2.1
Accurate error positions for config files truncated mid-value, via dependency updates.
Context
go-toml-edit v0.2.2 fixed ParseError positions for unexpected-EOF errors (previously reported as line 0, column 0), so dirstat's --config error messages are now accurate for every malformed-file shape. strictcli was bumped to v0.20.0 per the always-latest policy for internal dependencies; dirstat's CLI surface is unchanged (schema byte-identical), only the error for a pre-command --config token changed wording (strictcli's new reserved flag handling).
#Fixes
- Config files truncated mid-value (e.g. an unclosed array at end of file) now report an accurate line/column error position instead of
line 0, column 0. - Passing
--configbefore the command (dirstat --config x scan) now reports--config is not available: this app does not use config filesinstead ofunknown command '--config'. Thescan --configflag is unaffected.
#0.2.0
Scan config files via --config, and curated default excludes (including .git) for fast out-of-the-box scans.
Context
Real-world use showed that scanning large project trees requires the same ~20 --exclude flags every time (node_modules, .git, caches, build output), so dirstat now ships a curated default exclude list and an explicit TOML config mechanism. The config file is never auto-discovered: it is used only when --config
#Breaking
- Curated default excludes.
--excludenow defaults to a built-in list (.git,node_modules,.venv,vendor,build,dist,target,zig-out,zig-pkg,.next,.svelte-kit,__pycache__,.mypy_cache,.ruff_cache,.pytest_cache,.hypothesis,.gradle,.idea,.wrangler,.vscode), so default scan results change: files under those directories are no longer counted. Restore the old scan-everything behavior withexclude = []in a--configfile or any explicit--exclude(which replaces the list entirely, e.g.--exclude "").
#Features
- Scan config file. New
--config <path>flag reads scan defaults (exclude,method,depth,ignored,hidden,type,stats,sort_by,sort_order) from a TOML file. The file is fully validated before scanning, never auto-discovered, and setting a key both in the file and on the command line is a hard error. The active config path is shown as the first summary line and as an additiveconfigJSON field.
#0.1.0
Initial release: fast directory statistics with format grouping, size and LOC aggregates, colored tables, and stable JSON output.
Context
dirstat is a clean-slate Go redesign of an internal Python prototype. The rewrite eliminates all subprocesses (in-process gitignore matching and MIME sniffing), counts lines of code in parallel, and ships as a single static binary. JSON output is a stable consumer contract for downstream tooling.
#Features
- New tool.
dirstat scansummarizes the files under a directory grouped by format, with counts, sizes, and lines of code; supports ext/type/hybrid grouping, gitignore handling, hidden/exclude/depth filters, and multi-key sorting - Colored terminal tables with dark/light themes, unicode/ascii border styles, terminal-width adaptation, singleton collapsing, and a text/binary legend
- Machine-readable JSON output (
--output json) with a stable, additive-only schema