Skip to main content

wind_kit_diagnostics_contracts 1.3.0 copy "wind_kit_diagnostics_contracts: ^1.3.0" to clipboard
wind_kit_diagnostics_contracts: ^1.3.0 copied to clipboard

Read wind_kit widget state (className, breakpoint, brightness, states) from debug tools and AI agents without depending on wind_kit. Pure contracts, no UI.

wind_kit_diagnostics_contracts logo

wind_kit_diagnostics_contracts

Read wind_kit widget state without depending on wind_kit.
Pure abstract contracts and a process-global registry, so debug tools and AI agents see className, breakpoint, brightness and states while wind_kit and the tool stay strangers. Frozen v1 contract.

pub package CI codecov License: MIT pub points

Documentation · pub.dev · Issues

At a glance #

Fact Value
Package wind_kit_diagnostics_contracts
Install flutter pub add wind_kit_diagnostics_contracts
Import package:wind_kit_diagnostics_contracts/wind_kit_diagnostics_contracts.dart
Entry points WindDebugResolver (per-element widget state), WindPerfResolver (process-wide counters), WindDebugRegistry (the two slots)
Platforms All: plain Dart over Flutter's Element, no UI, no native code
Requires Dart >=3.4, Flutter >=3.27
Dependencies flutter and meta only
License MIT

Install #

flutter pub add wind_kit_diagnostics_contracts

Most apps never add it by hand: wind_kit depends on it, so any app that uses wind_kit already has it. Add it when you author a debug tool that reads wind_kit state.

Why it exists #

wind_kit knows each widget's resolved state (className, breakpoint, brightness, platform, states, colours). Debug tools such as tapir put that state in their snapshots so an LLM agent can reason about the rendered tree. Handing it over through wind_kit's own API would make every tool depend on wind_kit's whole rendering surface; the other way round would make wind_kit depend on every tool.

This package breaks the loop. Both sides depend on the contract here, and neither imports the other. It follows Flutter's *_platform_interface convention.

          wind_kit_diagnostics_contracts
                      |
        +-------------+-------------+
        |                           |
    wind_kit                      tapir
 (implements a resolver)  (reads it at snapshot time)

WindDebugResolver #

One method, resolve(Element), answers per-element widget state. An element with nothing to report (not a W-widget, or one without a className) resolves to an empty map, so a tool can walk any tree.

import 'package:flutter/widgets.dart';
import 'package:wind_kit_diagnostics_contracts/wind_kit_diagnostics_contracts.dart';

void emitWindBlock(StringBuffer buffer, Element element) {
  final WindDebugResolver? resolver = WindDebugRegistry.current;
  if (resolver == null) return; // wind_kit is not in this app, or this is a release build.

  final Map<String, Object?> data = resolver.resolve(element);
  if (data.isEmpty) return; // Nothing to report for this element.

  buffer.writeln('wind:');
  data.forEach((String key, Object? value) => buffer.writeln('  $key: $value'));
}
Key Type Present
className String For a W-widget with a non-empty className
breakpoint String sm, md, lg, ...
brightness String light or dark
platform String web, ios, android, macos, ...
states List<String> hover, focus, ...
bgColor, textColor String (hex) Only when resolved

WindPerfResolver #

A second, independent contract for numbers that belong to no single element: cache hits, build counts, inherited-widget reads. It has its own slot, and registering one contract never touches the other.

import 'package:wind_kit_diagnostics_contracts/wind_kit_diagnostics_contracts.dart';

Map<String, Object?>? readStats() {
  final WindPerfResolver? perf = WindDebugRegistry.currentPerf;
  if (perf == null) return null; // No resolver was ever registered.

  return perf.stats();
}

stats() returns cacheHits, cacheMisses, cacheBypasses, cacheSize, wDivBuilds and wTextBuilds as int, plus widgetBuilds, wrapperEmissions and inheritedReads as Map<String, int>. Keep the null: it tells "no resolver registered" apart from a resolver that reports zeros. A zero is ambiguous on its own, because wind_kit counts only during a measurement session (cacheSize is always live).

Registering #

The host app installs both resolvers through wind_kit at boot, behind !kReleaseMode, so a release build tree-shakes them. wind_kit never makes these calls itself:

import 'package:flutter/foundation.dart';
import 'package:wind_kit/wind_kit.dart';

void main() {
  if (!kReleaseMode) {
    Wind.installDebugResolver();
    Wind.installPerfResolver();
  }
}

Testing #

WindDebugRegistry ships three @visibleForTesting seams: resetForTesting() clears both slots, registerForTesting and registerPerfForTesting fill one each. See the testing guide.

For AI coding agents #

Rules for an agent writing code against this package. Each one is a mistake the maintainers already made once.

Do Because
Import only package:wind_kit_diagnostics_contracts/wind_kit_diagnostics_contracts.dart It is the only library; everything is public through it.
Read WindDebugRegistry.current and currentPerf on every use and handle null The host may install after your tool starts, or never (release build, no wind_kit, or no install call). null means no resolver; an empty map means the element has nothing to report.
Read the keys you need and ignore the rest A minor release adds keys. Renaming or removing one is a major bump.
Take per-type build counts from widgetBuilds, not wDivBuilds or wTextBuilds The two older keys duplicate widgetBuilds['WDiv'] and ['WText'] and stay only for the 1.x line.
Treat zeros in stats() as ambiguous wind_kit counts only during a measurement session, so a zero can mean it is off. Only cacheSize is always live.
Register through register and registerPerf, and call *ForTesting only from test/ The testing seams are @visibleForTesting; a fake installed through register reads as production wiring.
Call WindDebugRegistry.resetForTesting() in setUp or tearDown The registry is process-global and survives between tests.
Never add a method to either contract It breaks every implementer, test fakes included, so it is a major bump. Add a key, or a new contract.

Dependencies #

flutter (for Element) and meta (for @visibleForTesting). That is the whole surface, on purpose: a dependency added here is a dependency forced on wind_kit and every tool.

License #

MIT, see LICENSE. Built by Anılcan Çakır.

0
likes
160
points
--
downloads

Documentation

API reference

Publisher

verified publisheranilcancakir.com

Weekly Downloads

Read wind_kit widget state (className, breakpoint, brightness, states) from debug tools and AI agents without depending on wind_kit. Pure contracts, no UI.

Homepage
Repository (GitHub)
View/report issues

Topics

#diagnostics #debugging #devtools #ai-agents #tailwind

License

MIT (license)

Dependencies

flutter, meta

More

Packages that depend on wind_kit_diagnostics_contracts