@zakmandhro/bunti 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/AGENTS.md +65 -0
  2. package/README.md +81 -11
  3. package/dist/cli.d.ts +44 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +147 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/colors.d.ts +77 -7
  8. package/dist/colors.d.ts.map +1 -1
  9. package/dist/colors.js +238 -39
  10. package/dist/colors.js.map +1 -1
  11. package/dist/components/Box.d.ts +6 -0
  12. package/dist/components/Box.d.ts.map +1 -1
  13. package/dist/components/Box.js +5 -0
  14. package/dist/components/Box.js.map +1 -1
  15. package/dist/components/Button.d.ts +12 -2
  16. package/dist/components/Button.d.ts.map +1 -1
  17. package/dist/components/Button.js +35 -24
  18. package/dist/components/Button.js.map +1 -1
  19. package/dist/components/Card.d.ts +24 -2
  20. package/dist/components/Card.d.ts.map +1 -1
  21. package/dist/components/Card.js +56 -14
  22. package/dist/components/Card.js.map +1 -1
  23. package/dist/components/Header.d.ts +11 -1
  24. package/dist/components/Header.d.ts.map +1 -1
  25. package/dist/components/Header.js +12 -8
  26. package/dist/components/Header.js.map +1 -1
  27. package/dist/components/Input.d.ts +10 -1
  28. package/dist/components/Input.d.ts.map +1 -1
  29. package/dist/components/Input.js +172 -41
  30. package/dist/components/Input.js.map +1 -1
  31. package/dist/components/Link.d.ts +21 -0
  32. package/dist/components/Link.d.ts.map +1 -0
  33. package/dist/components/Link.js +29 -0
  34. package/dist/components/Link.js.map +1 -0
  35. package/dist/components/Modal.d.ts +25 -0
  36. package/dist/components/Modal.d.ts.map +1 -1
  37. package/dist/components/Modal.js +83 -24
  38. package/dist/components/Modal.js.map +1 -1
  39. package/dist/components/Progress.d.ts +27 -0
  40. package/dist/components/Progress.d.ts.map +1 -0
  41. package/dist/components/Progress.js +39 -0
  42. package/dist/components/Progress.js.map +1 -0
  43. package/dist/components/Spinner.d.ts +19 -0
  44. package/dist/components/Spinner.d.ts.map +1 -0
  45. package/dist/components/Spinner.js +27 -0
  46. package/dist/components/Spinner.js.map +1 -0
  47. package/dist/components/index.d.ts +3 -0
  48. package/dist/components/index.d.ts.map +1 -1
  49. package/dist/components/index.js +3 -0
  50. package/dist/components/index.js.map +1 -1
  51. package/dist/data/nf-glyphs.d.ts +11 -0
  52. package/dist/data/nf-glyphs.d.ts.map +1 -0
  53. package/dist/data/nf-glyphs.js +535 -0
  54. package/dist/data/nf-glyphs.js.map +1 -0
  55. package/dist/data/nf-names.d.ts +8 -0
  56. package/dist/data/nf-names.d.ts.map +1 -0
  57. package/dist/data/nf-names.js +2 -0
  58. package/dist/data/nf-names.js.map +1 -0
  59. package/dist/demo-registry.d.ts +27 -0
  60. package/dist/demo-registry.d.ts.map +1 -0
  61. package/dist/demo-registry.js +57 -0
  62. package/dist/demo-registry.js.map +1 -0
  63. package/dist/demos/2048.ts +743 -0
  64. package/dist/demos/animation.ts +246 -0
  65. package/dist/demos/demo-layout.ts +124 -0
  66. package/dist/demos/engine.ts +374 -0
  67. package/dist/demos/interaction.ts +91 -0
  68. package/dist/demos/login.ts +203 -0
  69. package/dist/demos/mission-control.ts +558 -0
  70. package/dist/demos/showcase.ts +224 -0
  71. package/dist/detect.d.ts +92 -3
  72. package/dist/detect.d.ts.map +1 -1
  73. package/dist/detect.js +218 -40
  74. package/dist/detect.js.map +1 -1
  75. package/dist/diagnostics.d.ts +73 -0
  76. package/dist/diagnostics.d.ts.map +1 -0
  77. package/dist/diagnostics.js +225 -0
  78. package/dist/diagnostics.js.map +1 -0
  79. package/dist/dsl/context.d.ts +11 -0
  80. package/dist/dsl/context.d.ts.map +1 -0
  81. package/dist/dsl/context.js +563 -0
  82. package/dist/dsl/context.js.map +1 -0
  83. package/dist/dsl/hooks.d.ts +12 -0
  84. package/dist/dsl/hooks.d.ts.map +1 -0
  85. package/dist/dsl/hooks.js +148 -0
  86. package/dist/dsl/hooks.js.map +1 -0
  87. package/dist/dsl/interaction.d.ts +16 -0
  88. package/dist/dsl/interaction.d.ts.map +1 -0
  89. package/dist/dsl/interaction.js +101 -0
  90. package/dist/dsl/interaction.js.map +1 -0
  91. package/dist/dsl/layers.d.ts +14 -0
  92. package/dist/dsl/layers.d.ts.map +1 -0
  93. package/dist/dsl/layers.js +87 -0
  94. package/dist/dsl/layers.js.map +1 -0
  95. package/dist/dsl/motion.d.ts +10 -0
  96. package/dist/dsl/motion.d.ts.map +1 -0
  97. package/dist/dsl/motion.js +150 -0
  98. package/dist/dsl/motion.js.map +1 -0
  99. package/dist/dsl/render.d.ts +22 -0
  100. package/dist/dsl/render.d.ts.map +1 -0
  101. package/dist/dsl/render.js +69 -0
  102. package/dist/dsl/render.js.map +1 -0
  103. package/dist/dsl/types.d.ts +510 -0
  104. package/dist/dsl/types.d.ts.map +1 -0
  105. package/dist/dsl/types.js +33 -0
  106. package/dist/dsl/types.js.map +1 -0
  107. package/dist/dsl.d.ts +13 -154
  108. package/dist/dsl.d.ts.map +1 -1
  109. package/dist/dsl.js +12 -658
  110. package/dist/dsl.js.map +1 -1
  111. package/dist/easing.d.ts +41 -1
  112. package/dist/easing.d.ts.map +1 -1
  113. package/dist/easing.js +105 -2
  114. package/dist/easing.js.map +1 -1
  115. package/dist/geometry.d.ts +39 -0
  116. package/dist/geometry.d.ts.map +1 -1
  117. package/dist/geometry.js +20 -0
  118. package/dist/geometry.js.map +1 -1
  119. package/dist/icons-full.d.ts +5 -0
  120. package/dist/icons-full.d.ts.map +1 -0
  121. package/dist/icons-full.js +31 -0
  122. package/dist/icons-full.js.map +1 -0
  123. package/dist/icons.d.ts +426 -5
  124. package/dist/icons.d.ts.map +1 -1
  125. package/dist/icons.js +144 -15
  126. package/dist/icons.js.map +1 -1
  127. package/dist/index.d.ts +93 -22
  128. package/dist/index.d.ts.map +1 -1
  129. package/dist/index.js +17 -7
  130. package/dist/index.js.map +1 -1
  131. package/dist/input.d.ts +177 -0
  132. package/dist/input.d.ts.map +1 -0
  133. package/dist/input.js +533 -0
  134. package/dist/input.js.map +1 -0
  135. package/dist/layout.d.ts +111 -6
  136. package/dist/layout.d.ts.map +1 -1
  137. package/dist/layout.js +163 -23
  138. package/dist/layout.js.map +1 -1
  139. package/dist/render.d.ts +33 -1
  140. package/dist/render.d.ts.map +1 -1
  141. package/dist/render.js +431 -116
  142. package/dist/render.js.map +1 -1
  143. package/dist/state.d.ts +137 -3
  144. package/dist/state.d.ts.map +1 -1
  145. package/dist/state.js +25 -0
  146. package/dist/state.js.map +1 -1
  147. package/dist/theme.d.ts +129 -0
  148. package/dist/theme.d.ts.map +1 -0
  149. package/dist/theme.js +167 -0
  150. package/dist/theme.js.map +1 -0
  151. package/dist/themes/catppuccin-mocha.d.ts +19 -0
  152. package/dist/themes/catppuccin-mocha.d.ts.map +1 -0
  153. package/dist/themes/catppuccin-mocha.js +36 -0
  154. package/dist/themes/catppuccin-mocha.js.map +1 -0
  155. package/dist/themes/dracula.d.ts +21 -0
  156. package/dist/themes/dracula.d.ts.map +1 -0
  157. package/dist/themes/dracula.js +37 -0
  158. package/dist/themes/dracula.js.map +1 -0
  159. package/dist/themes/github-light.d.ts +21 -0
  160. package/dist/themes/github-light.d.ts.map +1 -0
  161. package/dist/themes/github-light.js +36 -0
  162. package/dist/themes/github-light.js.map +1 -0
  163. package/dist/themes/index.d.ts +19 -0
  164. package/dist/themes/index.d.ts.map +1 -0
  165. package/dist/themes/index.js +17 -0
  166. package/dist/themes/index.js.map +1 -0
  167. package/dist/themes/nord.d.ts +23 -0
  168. package/dist/themes/nord.d.ts.map +1 -0
  169. package/dist/themes/nord.js +38 -0
  170. package/dist/themes/nord.js.map +1 -0
  171. package/dist/themes/one-dark-pro.d.ts +21 -0
  172. package/dist/themes/one-dark-pro.d.ts.map +1 -0
  173. package/dist/themes/one-dark-pro.js +36 -0
  174. package/dist/themes/one-dark-pro.js.map +1 -0
  175. package/dist/themes/tokyo-night.d.ts +20 -0
  176. package/dist/themes/tokyo-night.d.ts.map +1 -0
  177. package/dist/themes/tokyo-night.js +37 -0
  178. package/dist/themes/tokyo-night.js.map +1 -0
  179. package/dist/utils.d.ts +1 -0
  180. package/dist/utils.d.ts.map +1 -1
  181. package/dist/utils.js +1 -0
  182. package/dist/utils.js.map +1 -1
  183. package/dist/vendor/colors.d.ts +45 -0
  184. package/dist/vendor/colors.d.ts.map +1 -0
  185. package/dist/vendor/colors.js +72 -0
  186. package/dist/vendor/colors.js.map +1 -0
  187. package/llms.txt +79 -0
  188. package/package.json +23 -7
  189. package/dist/data/glyphs.d.ts +0 -5
  190. package/dist/data/glyphs.d.ts.map +0 -1
  191. package/dist/data/glyphs.js +0 -29
  192. package/dist/data/glyphs.js.map +0 -1
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Bunti Dev Diagnostics
3
+ *
4
+ * Non-fatal "you probably meant" hints that teach the API while you build.
5
+ * Hints are buffered (deduplicated) and flushed ONCE to stderr when the
6
+ * process exits — never mid-frame, so a warning can never tear an active
7
+ * render. All hints are suppressed when NODE_ENV=production or
8
+ * BUNTI_NO_HINTS=1.
9
+ *
10
+ * The icon engine's unknown-name warnings flow through the same buffer via
11
+ * registerHintFlusher(), so a session produces at most one hint block.
12
+ */
13
+ import type { Rect } from './geometry';
14
+ import type { ScreenOptions } from './state';
15
+ /** Lazily produces extra hint lines at flush time (used by the icon engine). */
16
+ type HintFlusher = () => string[];
17
+ /** True when dev hints are disabled (NODE_ENV=production or BUNTI_NO_HINTS=1). */
18
+ export declare function hintsSuppressed(): boolean;
19
+ /**
20
+ * Buffers a one-line dev hint (deduplicated by message). Never writes to
21
+ * the terminal directly — everything drains on process exit.
22
+ */
23
+ export declare function recordHint(message: string): void;
24
+ /**
25
+ * Registers a lazy hint-line producer drained at flush time. Lets modules
26
+ * with their own buffers (icons) share the single exit flush.
27
+ */
28
+ export declare function registerHintFlusher(flusher: HintFlusher): void;
29
+ /** Renders and clears every buffered hint; '' when there are none. */
30
+ export declare function drainHints(): string;
31
+ /** Exit-hook target: writes all buffered hints to stderr, once. */
32
+ export declare function flushHints(): void;
33
+ /** Capped two-row Levenshtein; returns cap+1 as soon as it can bail out. */
34
+ export declare function editDistance(a: string, b: string, cap: number): number;
35
+ /**
36
+ * Best "did you mean" candidate for a name: exact match wins, then
37
+ * prefix relationships, then capped edit distance (cap scales with
38
+ * length). Returns undefined when nothing is close enough.
39
+ */
40
+ export declare function nearestMatch(target: string, candidates: Iterable<string>): string | undefined;
41
+ /**
42
+ * Called on reads of ctx.lastKey / ctx.keys / keyPressed / isKeyHeld:
43
+ * hints once when neither keyboard nor mouse input was enabled, so the
44
+ * app can never receive what it is polling for.
45
+ */
46
+ export declare function hintInputReadWithoutKeyboard(options: ScreenOptions): void;
47
+ /**
48
+ * Called by the render loop: keyboard input only works on a real TTY —
49
+ * piped stdin (CI, `echo | bun app.ts`, agent harnesses) is ignored.
50
+ */
51
+ export declare function hintKeyboardStdinNotTTY(keyboardRequested: boolean, stdinIsTTY: boolean): void;
52
+ /**
53
+ * Marks a frame boundary for keyless-hook tracking: compares the two most
54
+ * recent completed frames and hints once when the positional hook count
55
+ * shrank or a slot changed type (useState <-> useAsync) — the signature of
56
+ * conditionally-called keyless hooks returning another call's state.
57
+ */
58
+ export declare function beginHookFrame(state: object): void;
59
+ /** Records one keyless hook call (positional index + hook kind). */
60
+ export declare function recordKeylessHook(state: object, index: number, kind: 'useState' | 'useAsync'): void;
61
+ /**
62
+ * Cheap per-frame heuristic run by flushFlow: top-level boxes paint
63
+ * directly to the screen buffer, so two intersecting rects mean one box
64
+ * painted over another with nothing controlling the stacking. Hints once,
65
+ * then stops checking. O(n²) over at most 50 rects per frame.
66
+ */
67
+ export declare function hintOverlappingBoxes(rects: Rect[] | undefined): void;
68
+ /** @internal Test hook: currently buffered hint messages. */
69
+ export declare function __bufferedHints(): string[];
70
+ /** @internal Test hook: clears buffered hints and one-shot latches. */
71
+ export declare function __resetHints(): void;
72
+ export {};
73
+ //# sourceMappingURL=diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,gFAAgF;AAChF,KAAK,WAAW,GAAG,MAAM,MAAM,EAAE,CAAC;AAMlC,kFAAkF;AAClF,wBAAgB,eAAe,IAAI,OAAO,CAIzC;AASD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAIhD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAG9D;AAED,sEAAsE;AACtE,wBAAgB,UAAU,IAAI,MAAM,CAOnC;AAED,mEAAmE;AACnE,wBAAgB,UAAU,IAAI,IAAI,CAIjC;AAID,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAiBtE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC3B,MAAM,GAAG,SAAS,CAqBpB;AAID;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAKzE;AAID;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,iBAAiB,EAAE,OAAO,EAC1B,UAAU,EAAE,OAAO,GAClB,IAAI,CAMN;AAgBD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAsBlD;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,UAAU,GAAG,UAAU,GAC5B,IAAI,CAKN;AAQD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,SAAS,GAAG,IAAI,CAwBpE;AAID,6DAA6D;AAC7D,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED,uEAAuE;AACvE,wBAAgB,YAAY,IAAI,IAAI,CAGnC"}
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Bunti Dev Diagnostics
3
+ *
4
+ * Non-fatal "you probably meant" hints that teach the API while you build.
5
+ * Hints are buffered (deduplicated) and flushed ONCE to stderr when the
6
+ * process exits — never mid-frame, so a warning can never tear an active
7
+ * render. All hints are suppressed when NODE_ENV=production or
8
+ * BUNTI_NO_HINTS=1.
9
+ *
10
+ * The icon engine's unknown-name warnings flow through the same buffer via
11
+ * registerHintFlusher(), so a session produces at most one hint block.
12
+ */
13
+ const hints = new Set();
14
+ const flushers = new Set();
15
+ let exitHookInstalled = false;
16
+ /** True when dev hints are disabled (NODE_ENV=production or BUNTI_NO_HINTS=1). */
17
+ export function hintsSuppressed() {
18
+ return (process.env.NODE_ENV === 'production' || process.env.BUNTI_NO_HINTS === '1');
19
+ }
20
+ function installExitHook() {
21
+ if (exitHookInstalled)
22
+ return;
23
+ exitHookInstalled = true;
24
+ // 'exit' handlers must stay synchronous; flushHints only writes a string.
25
+ process.on('exit', flushHints);
26
+ }
27
+ /**
28
+ * Buffers a one-line dev hint (deduplicated by message). Never writes to
29
+ * the terminal directly — everything drains on process exit.
30
+ */
31
+ export function recordHint(message) {
32
+ if (hintsSuppressed())
33
+ return;
34
+ hints.add(message);
35
+ installExitHook();
36
+ }
37
+ /**
38
+ * Registers a lazy hint-line producer drained at flush time. Lets modules
39
+ * with their own buffers (icons) share the single exit flush.
40
+ */
41
+ export function registerHintFlusher(flusher) {
42
+ flushers.add(flusher);
43
+ installExitHook();
44
+ }
45
+ /** Renders and clears every buffered hint; '' when there are none. */
46
+ export function drainHints() {
47
+ const lines = [...hints];
48
+ hints.clear();
49
+ for (const flusher of flushers)
50
+ lines.push(...flusher());
51
+ if (lines.length === 0)
52
+ return '';
53
+ const body = lines.map((line) => ` - ${line}`).join('\n');
54
+ return `\n[bunti] dev hints (set BUNTI_NO_HINTS=1 to silence):\n${body}\n`;
55
+ }
56
+ /** Exit-hook target: writes all buffered hints to stderr, once. */
57
+ export function flushHints() {
58
+ if (hintsSuppressed())
59
+ return;
60
+ const out = drainHints();
61
+ if (out)
62
+ process.stderr.write(out);
63
+ }
64
+ // --- Nearest-name matching (shared by icons and colors) ---
65
+ /** Capped two-row Levenshtein; returns cap+1 as soon as it can bail out. */
66
+ export function editDistance(a, b, cap) {
67
+ if (Math.abs(a.length - b.length) > cap)
68
+ return cap + 1;
69
+ let prev = new Array(b.length + 1);
70
+ let curr = new Array(b.length + 1);
71
+ for (let j = 0; j <= b.length; j++)
72
+ prev[j] = j;
73
+ for (let i = 1; i <= a.length; i++) {
74
+ curr[0] = i;
75
+ let rowMin = i;
76
+ for (let j = 1; j <= b.length; j++) {
77
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
78
+ curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
79
+ if (curr[j] < rowMin)
80
+ rowMin = curr[j];
81
+ }
82
+ if (rowMin > cap)
83
+ return cap + 1;
84
+ [prev, curr] = [curr, prev];
85
+ }
86
+ return prev[b.length];
87
+ }
88
+ /**
89
+ * Best "did you mean" candidate for a name: exact match wins, then
90
+ * prefix relationships, then capped edit distance (cap scales with
91
+ * length). Returns undefined when nothing is close enough.
92
+ */
93
+ export function nearestMatch(target, candidates) {
94
+ const cap = Math.max(2, Math.ceil(target.length / 3));
95
+ let best;
96
+ let bestScore = cap + 1;
97
+ for (const candidate of candidates) {
98
+ let score;
99
+ if (candidate === target) {
100
+ score = 0;
101
+ }
102
+ else if (candidate.startsWith(target) || target.startsWith(candidate)) {
103
+ score = 1;
104
+ }
105
+ else {
106
+ score = editDistance(target, candidate, cap);
107
+ }
108
+ if (score < bestScore) {
109
+ bestScore = score;
110
+ best = candidate;
111
+ if (score === 0)
112
+ return best;
113
+ }
114
+ }
115
+ return best;
116
+ }
117
+ // --- Hint 1: input read without keyboard/mouse enabled ---
118
+ /**
119
+ * Called on reads of ctx.lastKey / ctx.keys / keyPressed / isKeyHeld:
120
+ * hints once when neither keyboard nor mouse input was enabled, so the
121
+ * app can never receive what it is polling for.
122
+ */
123
+ export function hintInputReadWithoutKeyboard(options) {
124
+ if (options.keyboard === true || options.mouse === true)
125
+ return;
126
+ recordHint('keyboard input read but { keyboard: true } not set in render options');
127
+ }
128
+ // --- Hint 2: keyboard requested but stdin is not a TTY ---
129
+ /**
130
+ * Called by the render loop: keyboard input only works on a real TTY —
131
+ * piped stdin (CI, `echo | bun app.ts`, agent harnesses) is ignored.
132
+ */
133
+ export function hintKeyboardStdinNotTTY(keyboardRequested, stdinIsTTY) {
134
+ if (!keyboardRequested || stdinIsTTY)
135
+ return;
136
+ recordHint('keyboard requested but stdin is not a TTY (piped input is ignored); ' +
137
+ 'run in a real terminal or PTY');
138
+ }
139
+ const hookLogs = new WeakMap();
140
+ const HOOK_DRIFT_HINT = 'conditional keyless useState detected — pass a stable string key';
141
+ /**
142
+ * Marks a frame boundary for keyless-hook tracking: compares the two most
143
+ * recent completed frames and hints once when the positional hook count
144
+ * shrank or a slot changed type (useState <-> useAsync) — the signature of
145
+ * conditionally-called keyless hooks returning another call's state.
146
+ */
147
+ export function beginHookFrame(state) {
148
+ if (hintsSuppressed())
149
+ return;
150
+ const log = hookLogs.get(state);
151
+ if (!log) {
152
+ hookLogs.set(state, { prev: null, curr: [] });
153
+ return;
154
+ }
155
+ const { prev, curr } = log;
156
+ if (prev !== null) {
157
+ if (curr.length < prev.length) {
158
+ recordHint(HOOK_DRIFT_HINT);
159
+ }
160
+ else {
161
+ for (let i = 0; i < prev.length; i++) {
162
+ if (curr[i] !== undefined && curr[i] !== prev[i]) {
163
+ recordHint(HOOK_DRIFT_HINT);
164
+ break;
165
+ }
166
+ }
167
+ }
168
+ }
169
+ log.prev = curr;
170
+ log.curr = [];
171
+ }
172
+ /** Records one keyless hook call (positional index + hook kind). */
173
+ export function recordKeylessHook(state, index, kind) {
174
+ if (hintsSuppressed())
175
+ return;
176
+ const log = hookLogs.get(state);
177
+ if (!log)
178
+ return;
179
+ log.curr[index] = kind;
180
+ }
181
+ // --- Hint 4 lives in colors.ts (unknown color names, via nearestMatch) ---
182
+ // --- Hint 5: overlapping direct-rendered boxes without layers ---
183
+ let overlapHintRecorded = false;
184
+ /**
185
+ * Cheap per-frame heuristic run by flushFlow: top-level boxes paint
186
+ * directly to the screen buffer, so two intersecting rects mean one box
187
+ * painted over another with nothing controlling the stacking. Hints once,
188
+ * then stops checking. O(n²) over at most 50 rects per frame.
189
+ */
190
+ export function hintOverlappingBoxes(rects) {
191
+ if (overlapHintRecorded || !rects || rects.length < 2)
192
+ return;
193
+ if (hintsSuppressed())
194
+ return;
195
+ const n = Math.min(rects.length, 50);
196
+ for (let i = 0; i < n; i++) {
197
+ const a = rects[i];
198
+ if (a.width <= 0 || a.height <= 0)
199
+ continue;
200
+ for (let j = i + 1; j < n; j++) {
201
+ const b = rects[j];
202
+ if (b.width <= 0 || b.height <= 0)
203
+ continue;
204
+ if (a.x < b.x + b.width &&
205
+ b.x < a.x + a.width &&
206
+ a.y < b.y + b.height &&
207
+ b.y < a.y + a.height) {
208
+ overlapHintRecorded = true;
209
+ recordHint('overlapping boxes detected — use ctx.layer() or zIndex for overlays');
210
+ return;
211
+ }
212
+ }
213
+ }
214
+ }
215
+ // --- Test hooks ---
216
+ /** @internal Test hook: currently buffered hint messages. */
217
+ export function __bufferedHints() {
218
+ return [...hints];
219
+ }
220
+ /** @internal Test hook: clears buffered hints and one-shot latches. */
221
+ export function __resetHints() {
222
+ hints.clear();
223
+ overlapHintRecorded = false;
224
+ }
225
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;AAChC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAe,CAAC;AACxC,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B,kFAAkF;AAClF,MAAM,UAAU,eAAe;IAC7B,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,GAAG,CAC5E,CAAC;AACJ,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,iBAAiB;QAAE,OAAO;IAC9B,iBAAiB,GAAG,IAAI,CAAC;IACzB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,IAAI,eAAe,EAAE;QAAE,OAAO;IAC9B,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACnB,eAAe,EAAE,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAoB;IACtD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACtB,eAAe,EAAE,CAAC;AACpB,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,UAAU;IACxB,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IACzB,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,KAAK,MAAM,OAAO,IAAI,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,EAAE,CAAC,CAAC;IACzD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3D,OAAO,2DAA2D,IAAI,IAAI,CAAC;AAC7E,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,UAAU;IACxB,IAAI,eAAe,EAAE;QAAE,OAAO;IAC9B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,IAAI,GAAG;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,6DAA6D;AAE7D,4EAA4E;AAC5E,MAAM,UAAU,YAAY,CAAC,CAAS,EAAE,CAAS,EAAE,GAAW;IAC5D,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,GAAG;QAAE,OAAO,GAAG,GAAG,CAAC,CAAC;IACxD,IAAI,IAAI,GAAa,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,IAAI,IAAI,GAAa,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACZ,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YACrE,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM;gBAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,MAAM,GAAG,GAAG;YAAE,OAAO,GAAG,GAAG,CAAC,CAAC;QACjC,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAc,EACd,UAA4B;IAE5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IACtD,IAAI,IAAwB,CAAC;IAC7B,IAAI,SAAS,GAAG,GAAG,GAAG,CAAC,CAAC;IAExB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,KAAa,CAAC;QAClB,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YACzB,KAAK,GAAG,CAAC,CAAC;QACZ,CAAC;aAAM,IAAI,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACxE,KAAK,GAAG,CAAC,CAAC;QACZ,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;YACtB,SAAS,GAAG,KAAK,CAAC;YAClB,IAAI,GAAG,SAAS,CAAC;YACjB,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,4DAA4D;AAE5D;;;;GAIG;AACH,MAAM,UAAU,4BAA4B,CAAC,OAAsB;IACjE,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI;QAAE,OAAO;IAChE,UAAU,CACR,sEAAsE,CACvE,CAAC;AACJ,CAAC;AAED,4DAA4D;AAE5D;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,iBAA0B,EAC1B,UAAmB;IAEnB,IAAI,CAAC,iBAAiB,IAAI,UAAU;QAAE,OAAO;IAC7C,UAAU,CACR,sEAAsE;QACpE,+BAA+B,CAClC,CAAC;AACJ,CAAC;AAWD,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAwB,CAAC;AAErD,MAAM,eAAe,GACnB,kEAAkE,CAAC;AAErE;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,IAAI,eAAe,EAAE;QAAE,OAAO;IAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IACD,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC;IAC3B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC9B,UAAU,CAAC,eAAe,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;oBACjD,UAAU,CAAC,eAAe,CAAC,CAAC;oBAC5B,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;IAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;AAChB,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,iBAAiB,CAC/B,KAAa,EACb,KAAa,EACb,IAA6B;IAE7B,IAAI,eAAe,EAAE;QAAE,OAAO;IAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;AACzB,CAAC;AAED,4EAA4E;AAE5E,mEAAmE;AAEnE,IAAI,mBAAmB,GAAG,KAAK,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAyB;IAC5D,IAAI,mBAAmB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO;IAC9D,IAAI,eAAe,EAAE;QAAE,OAAO;IAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACpB,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC;YAAE,SAAS;QAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;YACpB,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC;gBAAE,SAAS;YAC5C,IACE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK;gBACnB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK;gBACnB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM;gBACpB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EACpB,CAAC;gBACD,mBAAmB,GAAG,IAAI,CAAC;gBAC3B,UAAU,CACR,qEAAqE,CACtE,CAAC;gBACF,OAAO;YACT,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,qBAAqB;AAErB,6DAA6D;AAC7D,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY;IAC1B,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,mBAAmB,GAAG,KAAK,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Bunti DSL context factories: the common per-closure context, the direct
3
+ * (screen-buffer) box renderer, and the top-level screen context.
4
+ */
5
+ import type { ScreenState } from '../state';
6
+ import { type BuntiContext } from './types';
7
+ /**
8
+ * Top-level Screen Context
9
+ */
10
+ export declare function createScreenContext(state: ScreenState): BuntiContext;
11
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/dsl/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+CH,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,UAAU,CAAC;AAkBvD,OAAO,EACL,KAAK,YAAY,EAKlB,MAAM,SAAS,CAAC;AA2oBjB;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CA2GpE"}