@inhuman.tools/quickdraw 0.0.0-stage → 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 (522) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +101 -2
  3. package/aurora.vert +168 -0
  4. package/dist/bench/host.d.ts +62 -0
  5. package/dist/bench/host.d.ts.map +1 -0
  6. package/dist/bench/host.js +77 -0
  7. package/dist/bench/host.js.map +1 -0
  8. package/dist/bench/main.d.ts +6 -0
  9. package/dist/bench/main.d.ts.map +1 -0
  10. package/dist/bench/main.js +118 -0
  11. package/dist/bench/main.js.map +1 -0
  12. package/dist/bench/model.d.ts +36 -0
  13. package/dist/bench/model.d.ts.map +1 -0
  14. package/dist/bench/model.js +112 -0
  15. package/dist/bench/model.js.map +1 -0
  16. package/dist/bench/tea.d.ts +14 -0
  17. package/dist/bench/tea.d.ts.map +1 -0
  18. package/dist/bench/tea.js +6 -0
  19. package/dist/bench/tea.js.map +1 -0
  20. package/dist/bench/view.d.ts +9 -0
  21. package/dist/bench/view.d.ts.map +1 -0
  22. package/dist/bench/view.js +88 -0
  23. package/dist/bench/view.js.map +1 -0
  24. package/dist/bench/worker.d.ts +6 -0
  25. package/dist/bench/worker.d.ts.map +1 -0
  26. package/dist/bench/worker.js +46 -0
  27. package/dist/bench/worker.js.map +1 -0
  28. package/dist/buffer/bgfx-mark.d.ts +32 -0
  29. package/dist/buffer/bgfx-mark.d.ts.map +1 -0
  30. package/dist/buffer/bgfx-mark.js +43 -0
  31. package/dist/buffer/bgfx-mark.js.map +1 -0
  32. package/dist/buffer/index.d.ts +191 -0
  33. package/dist/buffer/index.d.ts.map +1 -0
  34. package/dist/buffer/index.js +353 -0
  35. package/dist/buffer/index.js.map +1 -0
  36. package/dist/capabilities/env.d.ts +23 -0
  37. package/dist/capabilities/env.d.ts.map +1 -0
  38. package/dist/capabilities/env.js +35 -0
  39. package/dist/capabilities/env.js.map +1 -0
  40. package/dist/capabilities/index.d.ts +13 -0
  41. package/dist/capabilities/index.d.ts.map +1 -0
  42. package/dist/capabilities/index.js +13 -0
  43. package/dist/capabilities/index.js.map +1 -0
  44. package/dist/capabilities/parse.d.ts +41 -0
  45. package/dist/capabilities/parse.d.ts.map +1 -0
  46. package/dist/capabilities/parse.js +86 -0
  47. package/dist/capabilities/parse.js.map +1 -0
  48. package/dist/capabilities/probe.d.ts +37 -0
  49. package/dist/capabilities/probe.d.ts.map +1 -0
  50. package/dist/capabilities/probe.js +75 -0
  51. package/dist/capabilities/probe.js.map +1 -0
  52. package/dist/capabilities/sequences.d.ts +33 -0
  53. package/dist/capabilities/sequences.d.ts.map +1 -0
  54. package/dist/capabilities/sequences.js +36 -0
  55. package/dist/capabilities/sequences.js.map +1 -0
  56. package/dist/capabilities/types.d.ts +25 -0
  57. package/dist/capabilities/types.d.ts.map +1 -0
  58. package/dist/capabilities/types.js +5 -0
  59. package/dist/capabilities/types.js.map +1 -0
  60. package/dist/index.d.ts +11 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +11 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/input/decode.d.ts +167 -0
  65. package/dist/input/decode.d.ts.map +1 -0
  66. package/dist/input/decode.js +825 -0
  67. package/dist/input/decode.js.map +1 -0
  68. package/dist/input/draft.d.ts +85 -0
  69. package/dist/input/draft.d.ts.map +1 -0
  70. package/dist/input/draft.js +276 -0
  71. package/dist/input/draft.js.map +1 -0
  72. package/dist/input/index.d.ts +3 -0
  73. package/dist/input/index.d.ts.map +1 -0
  74. package/dist/input/index.js +3 -0
  75. package/dist/input/index.js.map +1 -0
  76. package/dist/input/prompt-blocks.d.ts +58 -0
  77. package/dist/input/prompt-blocks.d.ts.map +1 -0
  78. package/dist/input/prompt-blocks.js +48 -0
  79. package/dist/input/prompt-blocks.js.map +1 -0
  80. package/dist/input/rich-draft.d.ts +46 -0
  81. package/dist/input/rich-draft.d.ts.map +1 -0
  82. package/dist/input/rich-draft.js +391 -0
  83. package/dist/input/rich-draft.js.map +1 -0
  84. package/dist/input/rich-hit.d.ts +17 -0
  85. package/dist/input/rich-hit.d.ts.map +1 -0
  86. package/dist/input/rich-hit.js +89 -0
  87. package/dist/input/rich-hit.js.map +1 -0
  88. package/dist/input/rich-intake.d.ts +16 -0
  89. package/dist/input/rich-intake.d.ts.map +1 -0
  90. package/dist/input/rich-intake.js +22 -0
  91. package/dist/input/rich-intake.js.map +1 -0
  92. package/dist/input/rich-paint.d.ts +13 -0
  93. package/dist/input/rich-paint.d.ts.map +1 -0
  94. package/dist/input/rich-paint.js +18 -0
  95. package/dist/input/rich-paint.js.map +1 -0
  96. package/dist/internals/bgfx/index.d.ts +17 -0
  97. package/dist/internals/bgfx/index.d.ts.map +1 -0
  98. package/dist/internals/bgfx/index.js +17 -0
  99. package/dist/internals/bgfx/index.js.map +1 -0
  100. package/dist/internals/bgfx/materialize.d.ts +31 -0
  101. package/dist/internals/bgfx/materialize.d.ts.map +1 -0
  102. package/dist/internals/bgfx/materialize.js +117 -0
  103. package/dist/internals/bgfx/materialize.js.map +1 -0
  104. package/dist/internals/bgfx/opacity.d.ts +37 -0
  105. package/dist/internals/bgfx/opacity.d.ts.map +1 -0
  106. package/dist/internals/bgfx/opacity.js +76 -0
  107. package/dist/internals/bgfx/opacity.js.map +1 -0
  108. package/dist/internals/bgfx/registry.d.ts +13 -0
  109. package/dist/internals/bgfx/registry.d.ts.map +1 -0
  110. package/dist/internals/bgfx/registry.js +24 -0
  111. package/dist/internals/bgfx/registry.js.map +1 -0
  112. package/dist/internals/bgfx/sab-layout.d.ts +61 -0
  113. package/dist/internals/bgfx/sab-layout.d.ts.map +1 -0
  114. package/dist/internals/bgfx/sab-layout.js +107 -0
  115. package/dist/internals/bgfx/sab-layout.js.map +1 -0
  116. package/dist/internals/bgfx/shader-frame-host.d.ts +22 -0
  117. package/dist/internals/bgfx/shader-frame-host.d.ts.map +1 -0
  118. package/dist/internals/bgfx/shader-frame-host.js +165 -0
  119. package/dist/internals/bgfx/shader-frame-host.js.map +1 -0
  120. package/dist/internals/bgfx/shadertoy-catalog.d.ts +41 -0
  121. package/dist/internals/bgfx/shadertoy-catalog.d.ts.map +1 -0
  122. package/dist/internals/bgfx/shadertoy-catalog.js +200 -0
  123. package/dist/internals/bgfx/shadertoy-catalog.js.map +1 -0
  124. package/dist/internals/bgfx/shadertoy-gl.d.ts +38 -0
  125. package/dist/internals/bgfx/shadertoy-gl.d.ts.map +1 -0
  126. package/dist/internals/bgfx/shadertoy-gl.js +283 -0
  127. package/dist/internals/bgfx/shadertoy-gl.js.map +1 -0
  128. package/dist/internals/bgfx/types.d.ts +51 -0
  129. package/dist/internals/bgfx/types.d.ts.map +1 -0
  130. package/dist/internals/bgfx/types.js +14 -0
  131. package/dist/internals/bgfx/types.js.map +1 -0
  132. package/dist/internals/bgfx-worker.d.ts +6 -0
  133. package/dist/internals/bgfx-worker.d.ts.map +1 -0
  134. package/dist/internals/bgfx-worker.js +131 -0
  135. package/dist/internals/bgfx-worker.js.map +1 -0
  136. package/dist/layout/birth.d.ts +77 -0
  137. package/dist/layout/birth.d.ts.map +1 -0
  138. package/dist/layout/birth.js +148 -0
  139. package/dist/layout/birth.js.map +1 -0
  140. package/dist/layout/children.d.ts +5 -0
  141. package/dist/layout/children.d.ts.map +1 -0
  142. package/dist/layout/children.js +19 -0
  143. package/dist/layout/children.js.map +1 -0
  144. package/dist/layout/chrome_frame.d.ts +254 -0
  145. package/dist/layout/chrome_frame.d.ts.map +1 -0
  146. package/dist/layout/chrome_frame.js +1080 -0
  147. package/dist/layout/chrome_frame.js.map +1 -0
  148. package/dist/layout/chrome_mask.d.ts +40 -0
  149. package/dist/layout/chrome_mask.d.ts.map +1 -0
  150. package/dist/layout/chrome_mask.js +150 -0
  151. package/dist/layout/chrome_mask.js.map +1 -0
  152. package/dist/layout/engine.d.ts +49 -0
  153. package/dist/layout/engine.d.ts.map +1 -0
  154. package/dist/layout/engine.js +1269 -0
  155. package/dist/layout/engine.js.map +1 -0
  156. package/dist/layout/flex.d.ts +36 -0
  157. package/dist/layout/flex.d.ts.map +1 -0
  158. package/dist/layout/flex.js +111 -0
  159. package/dist/layout/flex.js.map +1 -0
  160. package/dist/layout/grid.d.ts +36 -0
  161. package/dist/layout/grid.d.ts.map +1 -0
  162. package/dist/layout/grid.js +126 -0
  163. package/dist/layout/grid.js.map +1 -0
  164. package/dist/layout/index.d.ts +30 -0
  165. package/dist/layout/index.d.ts.map +1 -0
  166. package/dist/layout/index.js +30 -0
  167. package/dist/layout/index.js.map +1 -0
  168. package/dist/layout/indication.d.ts +34 -0
  169. package/dist/layout/indication.d.ts.map +1 -0
  170. package/dist/layout/indication.js +68 -0
  171. package/dist/layout/indication.js.map +1 -0
  172. package/dist/layout/length.d.ts +18 -0
  173. package/dist/layout/length.d.ts.map +1 -0
  174. package/dist/layout/length.js +24 -0
  175. package/dist/layout/length.js.map +1 -0
  176. package/dist/layout/live_paint.d.ts +145 -0
  177. package/dist/layout/live_paint.d.ts.map +1 -0
  178. package/dist/layout/live_paint.js +255 -0
  179. package/dist/layout/live_paint.js.map +1 -0
  180. package/dist/layout/markdown.d.ts +22 -0
  181. package/dist/layout/markdown.d.ts.map +1 -0
  182. package/dist/layout/markdown.js +167 -0
  183. package/dist/layout/markdown.js.map +1 -0
  184. package/dist/layout/measure.d.ts +46 -0
  185. package/dist/layout/measure.d.ts.map +1 -0
  186. package/dist/layout/measure.js +307 -0
  187. package/dist/layout/measure.js.map +1 -0
  188. package/dist/layout/paint-hotkey.d.ts +45 -0
  189. package/dist/layout/paint-hotkey.d.ts.map +1 -0
  190. package/dist/layout/paint-hotkey.js +152 -0
  191. package/dist/layout/paint-hotkey.js.map +1 -0
  192. package/dist/layout/paint.d.ts +25 -0
  193. package/dist/layout/paint.d.ts.map +1 -0
  194. package/dist/layout/paint.js +189 -0
  195. package/dist/layout/paint.js.map +1 -0
  196. package/dist/layout/paint_theme.d.ts +85 -0
  197. package/dist/layout/paint_theme.d.ts.map +1 -0
  198. package/dist/layout/paint_theme.js +76 -0
  199. package/dist/layout/paint_theme.js.map +1 -0
  200. package/dist/layout/progress.d.ts +31 -0
  201. package/dist/layout/progress.d.ts.map +1 -0
  202. package/dist/layout/progress.js +83 -0
  203. package/dist/layout/progress.js.map +1 -0
  204. package/dist/layout/selection.d.ts +136 -0
  205. package/dist/layout/selection.d.ts.map +1 -0
  206. package/dist/layout/selection.js +312 -0
  207. package/dist/layout/selection.js.map +1 -0
  208. package/dist/layout/selection_gesture.d.ts +88 -0
  209. package/dist/layout/selection_gesture.d.ts.map +1 -0
  210. package/dist/layout/selection_gesture.js +239 -0
  211. package/dist/layout/selection_gesture.js.map +1 -0
  212. package/dist/layout/selection_paint.d.ts +47 -0
  213. package/dist/layout/selection_paint.d.ts.map +1 -0
  214. package/dist/layout/selection_paint.js +320 -0
  215. package/dist/layout/selection_paint.js.map +1 -0
  216. package/dist/layout/serialize.d.ts +49 -0
  217. package/dist/layout/serialize.d.ts.map +1 -0
  218. package/dist/layout/serialize.js +437 -0
  219. package/dist/layout/serialize.js.map +1 -0
  220. package/dist/layout/squeeze.d.ts +58 -0
  221. package/dist/layout/squeeze.d.ts.map +1 -0
  222. package/dist/layout/squeeze.js +239 -0
  223. package/dist/layout/squeeze.js.map +1 -0
  224. package/dist/layout/text.d.ts +44 -0
  225. package/dist/layout/text.d.ts.map +1 -0
  226. package/dist/layout/text.js +230 -0
  227. package/dist/layout/text.js.map +1 -0
  228. package/dist/layout/theme_store.d.ts +21 -0
  229. package/dist/layout/theme_store.d.ts.map +1 -0
  230. package/dist/layout/theme_store.js +133 -0
  231. package/dist/layout/theme_store.js.map +1 -0
  232. package/dist/layout/types.d.ts +564 -0
  233. package/dist/layout/types.d.ts.map +1 -0
  234. package/dist/layout/types.js +2 -0
  235. package/dist/layout/types.js.map +1 -0
  236. package/dist/layout/visual_draft.d.ts +60 -0
  237. package/dist/layout/visual_draft.d.ts.map +1 -0
  238. package/dist/layout/visual_draft.js +199 -0
  239. package/dist/layout/visual_draft.js.map +1 -0
  240. package/dist/lexicon/color.d.ts +22 -0
  241. package/dist/lexicon/color.d.ts.map +1 -0
  242. package/dist/lexicon/color.js +6 -0
  243. package/dist/lexicon/color.js.map +1 -0
  244. package/dist/lexicon/index.d.ts +15 -0
  245. package/dist/lexicon/index.d.ts.map +1 -0
  246. package/dist/lexicon/index.js +15 -0
  247. package/dist/lexicon/index.js.map +1 -0
  248. package/dist/lexicon/prominence.d.ts +46 -0
  249. package/dist/lexicon/prominence.d.ts.map +1 -0
  250. package/dist/lexicon/prominence.js +73 -0
  251. package/dist/lexicon/prominence.js.map +1 -0
  252. package/dist/lexicon/quarantine.d.ts +21 -0
  253. package/dist/lexicon/quarantine.d.ts.map +1 -0
  254. package/dist/lexicon/quarantine.js +15 -0
  255. package/dist/lexicon/quarantine.js.map +1 -0
  256. package/dist/lexicon/roles.d.ts +37 -0
  257. package/dist/lexicon/roles.d.ts.map +1 -0
  258. package/dist/lexicon/roles.js +52 -0
  259. package/dist/lexicon/roles.js.map +1 -0
  260. package/dist/lexicon/tiers.d.ts +18 -0
  261. package/dist/lexicon/tiers.d.ts.map +1 -0
  262. package/dist/lexicon/tiers.js +17 -0
  263. package/dist/lexicon/tiers.js.map +1 -0
  264. package/dist/measure/index.d.ts +43 -0
  265. package/dist/measure/index.d.ts.map +1 -0
  266. package/dist/measure/index.js +120 -0
  267. package/dist/measure/index.js.map +1 -0
  268. package/dist/render.d.ts +72 -0
  269. package/dist/render.d.ts.map +1 -0
  270. package/dist/render.js +164 -0
  271. package/dist/render.js.map +1 -0
  272. package/dist/runtime/agents_keys.d.ts +8 -0
  273. package/dist/runtime/agents_keys.d.ts.map +1 -0
  274. package/dist/runtime/agents_keys.js +24 -0
  275. package/dist/runtime/agents_keys.js.map +1 -0
  276. package/dist/runtime/agents_peek.d.ts +44 -0
  277. package/dist/runtime/agents_peek.d.ts.map +1 -0
  278. package/dist/runtime/agents_peek.js +96 -0
  279. package/dist/runtime/agents_peek.js.map +1 -0
  280. package/dist/runtime/agents_preview.d.ts +27 -0
  281. package/dist/runtime/agents_preview.d.ts.map +1 -0
  282. package/dist/runtime/agents_preview.js +122 -0
  283. package/dist/runtime/agents_preview.js.map +1 -0
  284. package/dist/runtime/box_bus.d.ts +144 -0
  285. package/dist/runtime/box_bus.d.ts.map +1 -0
  286. package/dist/runtime/box_bus.js +74 -0
  287. package/dist/runtime/box_bus.js.map +1 -0
  288. package/dist/runtime/clipboard-image.d.ts +20 -0
  289. package/dist/runtime/clipboard-image.d.ts.map +1 -0
  290. package/dist/runtime/clipboard-image.js +62 -0
  291. package/dist/runtime/clipboard-image.js.map +1 -0
  292. package/dist/runtime/copy_toast.d.ts +46 -0
  293. package/dist/runtime/copy_toast.d.ts.map +1 -0
  294. package/dist/runtime/copy_toast.js +117 -0
  295. package/dist/runtime/copy_toast.js.map +1 -0
  296. package/dist/runtime/echo.d.ts +41 -0
  297. package/dist/runtime/echo.d.ts.map +1 -0
  298. package/dist/runtime/echo.js +112 -0
  299. package/dist/runtime/echo.js.map +1 -0
  300. package/dist/runtime/frame.d.ts +79 -0
  301. package/dist/runtime/frame.d.ts.map +1 -0
  302. package/dist/runtime/frame.js +258 -0
  303. package/dist/runtime/frame.js.map +1 -0
  304. package/dist/runtime/index.d.ts +16 -0
  305. package/dist/runtime/index.d.ts.map +1 -0
  306. package/dist/runtime/index.js +16 -0
  307. package/dist/runtime/index.js.map +1 -0
  308. package/dist/runtime/key_buffer.d.ts +19 -0
  309. package/dist/runtime/key_buffer.d.ts.map +1 -0
  310. package/dist/runtime/key_buffer.js +24 -0
  311. package/dist/runtime/key_buffer.js.map +1 -0
  312. package/dist/runtime/keys.d.ts +66 -0
  313. package/dist/runtime/keys.d.ts.map +1 -0
  314. package/dist/runtime/keys.js +220 -0
  315. package/dist/runtime/keys.js.map +1 -0
  316. package/dist/runtime/paint_snapshot.d.ts +9 -0
  317. package/dist/runtime/paint_snapshot.d.ts.map +1 -0
  318. package/dist/runtime/paint_snapshot.js +8 -0
  319. package/dist/runtime/paint_snapshot.js.map +1 -0
  320. package/dist/runtime/paint_source.d.ts +266 -0
  321. package/dist/runtime/paint_source.d.ts.map +1 -0
  322. package/dist/runtime/paint_source.js +532 -0
  323. package/dist/runtime/paint_source.js.map +1 -0
  324. package/dist/runtime/present_loop.d.ts +11 -0
  325. package/dist/runtime/present_loop.d.ts.map +1 -0
  326. package/dist/runtime/present_loop.js +46 -0
  327. package/dist/runtime/present_loop.js.map +1 -0
  328. package/dist/runtime/present_profile.d.ts +58 -0
  329. package/dist/runtime/present_profile.d.ts.map +1 -0
  330. package/dist/runtime/present_profile.js +130 -0
  331. package/dist/runtime/present_profile.js.map +1 -0
  332. package/dist/runtime/raster.d.ts +24 -0
  333. package/dist/runtime/raster.d.ts.map +1 -0
  334. package/dist/runtime/raster.js +43 -0
  335. package/dist/runtime/raster.js.map +1 -0
  336. package/dist/runtime/renderer.d.ts +151 -0
  337. package/dist/runtime/renderer.d.ts.map +1 -0
  338. package/dist/runtime/renderer.js +1607 -0
  339. package/dist/runtime/renderer.js.map +1 -0
  340. package/dist/runtime/screenshot.d.ts +9 -0
  341. package/dist/runtime/screenshot.d.ts.map +1 -0
  342. package/dist/runtime/screenshot.js +111 -0
  343. package/dist/runtime/screenshot.js.map +1 -0
  344. package/dist/runtime/selection_host.d.ts +41 -0
  345. package/dist/runtime/selection_host.d.ts.map +1 -0
  346. package/dist/runtime/selection_host.js +190 -0
  347. package/dist/runtime/selection_host.js.map +1 -0
  348. package/dist/runtime/stderr_hold.d.ts +16 -0
  349. package/dist/runtime/stderr_hold.d.ts.map +1 -0
  350. package/dist/runtime/stderr_hold.js +23 -0
  351. package/dist/runtime/stderr_hold.js.map +1 -0
  352. package/dist/runtime/thought_birth.d.ts +25 -0
  353. package/dist/runtime/thought_birth.d.ts.map +1 -0
  354. package/dist/runtime/thought_birth.js +122 -0
  355. package/dist/runtime/thought_birth.js.map +1 -0
  356. package/dist/runtime/thought_collapsed.d.ts +35 -0
  357. package/dist/runtime/thought_collapsed.d.ts.map +1 -0
  358. package/dist/runtime/thought_collapsed.js +94 -0
  359. package/dist/runtime/thought_collapsed.js.map +1 -0
  360. package/dist/runtime/tty.d.ts +58 -0
  361. package/dist/runtime/tty.d.ts.map +1 -0
  362. package/dist/runtime/tty.js +130 -0
  363. package/dist/runtime/tty.js.map +1 -0
  364. package/dist/theme/ansi16.d.ts +34 -0
  365. package/dist/theme/ansi16.d.ts.map +1 -0
  366. package/dist/theme/ansi16.js +181 -0
  367. package/dist/theme/ansi16.js.map +1 -0
  368. package/dist/theme/ansi256.d.ts +15 -0
  369. package/dist/theme/ansi256.d.ts.map +1 -0
  370. package/dist/theme/ansi256.js +94 -0
  371. package/dist/theme/ansi256.js.map +1 -0
  372. package/dist/theme/ground.d.ts +8 -0
  373. package/dist/theme/ground.d.ts.map +1 -0
  374. package/dist/theme/ground.js +11 -0
  375. package/dist/theme/ground.js.map +1 -0
  376. package/dist/theme/index.d.ts +10 -0
  377. package/dist/theme/index.d.ts.map +1 -0
  378. package/dist/theme/index.js +10 -0
  379. package/dist/theme/index.js.map +1 -0
  380. package/dist/theme/region.d.ts +42 -0
  381. package/dist/theme/region.d.ts.map +1 -0
  382. package/dist/theme/region.js +105 -0
  383. package/dist/theme/region.js.map +1 -0
  384. package/dist/theme/resolver.d.ts +126 -0
  385. package/dist/theme/resolver.d.ts.map +1 -0
  386. package/dist/theme/resolver.js +366 -0
  387. package/dist/theme/resolver.js.map +1 -0
  388. package/dist/theme/salience.d.ts +90 -0
  389. package/dist/theme/salience.d.ts.map +1 -0
  390. package/dist/theme/salience.js +208 -0
  391. package/dist/theme/salience.js.map +1 -0
  392. package/dist/theme/seeds.d.ts +113 -0
  393. package/dist/theme/seeds.d.ts.map +1 -0
  394. package/dist/theme/seeds.js +52 -0
  395. package/dist/theme/seeds.js.map +1 -0
  396. package/dist/theme/selection.d.ts +94 -0
  397. package/dist/theme/selection.d.ts.map +1 -0
  398. package/dist/theme/selection.js +135 -0
  399. package/dist/theme/selection.js.map +1 -0
  400. package/dist/theme/theme.d.ts +41 -0
  401. package/dist/theme/theme.d.ts.map +1 -0
  402. package/dist/theme/theme.js +34 -0
  403. package/dist/theme/theme.js.map +1 -0
  404. package/dist/widgets/composer-caret.d.ts +47 -0
  405. package/dist/widgets/composer-caret.d.ts.map +1 -0
  406. package/dist/widgets/composer-caret.js +90 -0
  407. package/dist/widgets/composer-caret.js.map +1 -0
  408. package/dist/widgets/composer-click.d.ts +30 -0
  409. package/dist/widgets/composer-click.d.ts.map +1 -0
  410. package/dist/widgets/composer-click.js +89 -0
  411. package/dist/widgets/composer-click.js.map +1 -0
  412. package/dist/widgets/composer-command.d.ts +64 -0
  413. package/dist/widgets/composer-command.d.ts.map +1 -0
  414. package/dist/widgets/composer-command.js +127 -0
  415. package/dist/widgets/composer-command.js.map +1 -0
  416. package/dist/widgets/composer-frame.d.ts +74 -0
  417. package/dist/widgets/composer-frame.d.ts.map +1 -0
  418. package/dist/widgets/composer-frame.js +284 -0
  419. package/dist/widgets/composer-frame.js.map +1 -0
  420. package/dist/widgets/composer-picker.d.ts +89 -0
  421. package/dist/widgets/composer-picker.d.ts.map +1 -0
  422. package/dist/widgets/composer-picker.js +240 -0
  423. package/dist/widgets/composer-picker.js.map +1 -0
  424. package/dist/widgets/diff.d.ts +11 -0
  425. package/dist/widgets/diff.d.ts.map +1 -0
  426. package/dist/widgets/diff.js +19 -0
  427. package/dist/widgets/diff.js.map +1 -0
  428. package/dist/widgets/expand.d.ts +28 -0
  429. package/dist/widgets/expand.d.ts.map +1 -0
  430. package/dist/widgets/expand.js +94 -0
  431. package/dist/widgets/expand.js.map +1 -0
  432. package/dist/widgets/index.d.ts +126 -0
  433. package/dist/widgets/index.d.ts.map +1 -0
  434. package/dist/widgets/index.js +455 -0
  435. package/dist/widgets/index.js.map +1 -0
  436. package/dist/widgets/internals/arrival-lang.d.ts +88 -0
  437. package/dist/widgets/internals/arrival-lang.d.ts.map +1 -0
  438. package/dist/widgets/internals/arrival-lang.js +211 -0
  439. package/dist/widgets/internals/arrival-lang.js.map +1 -0
  440. package/dist/widgets/internals/diff-expand.d.ts +93 -0
  441. package/dist/widgets/internals/diff-expand.d.ts.map +1 -0
  442. package/dist/widgets/internals/diff-expand.js +1106 -0
  443. package/dist/widgets/internals/diff-expand.js.map +1 -0
  444. package/dist/widgets/internals/embedded-syntax.d.ts +62 -0
  445. package/dist/widgets/internals/embedded-syntax.d.ts.map +1 -0
  446. package/dist/widgets/internals/embedded-syntax.js +465 -0
  447. package/dist/widgets/internals/embedded-syntax.js.map +1 -0
  448. package/dist/widgets/internals/markdown-expand.d.ts +57 -0
  449. package/dist/widgets/internals/markdown-expand.d.ts.map +1 -0
  450. package/dist/widgets/internals/markdown-expand.js +980 -0
  451. package/dist/widgets/internals/markdown-expand.js.map +1 -0
  452. package/dist/widgets/internals/overlay-syntax.d.ts +24 -0
  453. package/dist/widgets/internals/overlay-syntax.d.ts.map +1 -0
  454. package/dist/widgets/internals/overlay-syntax.js +90 -0
  455. package/dist/widgets/internals/overlay-syntax.js.map +1 -0
  456. package/dist/widgets/internals/pierre-parse/cleanLastNewline.d.ts +6 -0
  457. package/dist/widgets/internals/pierre-parse/cleanLastNewline.d.ts.map +1 -0
  458. package/dist/widgets/internals/pierre-parse/cleanLastNewline.js +8 -0
  459. package/dist/widgets/internals/pierre-parse/cleanLastNewline.js.map +1 -0
  460. package/dist/widgets/internals/pierre-parse/constants.d.ts +13 -0
  461. package/dist/widgets/internals/pierre-parse/constants.d.ts.map +1 -0
  462. package/dist/widgets/internals/pierre-parse/constants.js +13 -0
  463. package/dist/widgets/internals/pierre-parse/constants.js.map +1 -0
  464. package/dist/widgets/internals/pierre-parse/detachString.d.ts +3 -0
  465. package/dist/widgets/internals/pierre-parse/detachString.d.ts.map +1 -0
  466. package/dist/widgets/internals/pierre-parse/detachString.js +24 -0
  467. package/dist/widgets/internals/pierre-parse/detachString.js.map +1 -0
  468. package/dist/widgets/internals/pierre-parse/index.d.ts +8 -0
  469. package/dist/widgets/internals/pierre-parse/index.d.ts.map +1 -0
  470. package/dist/widgets/internals/pierre-parse/index.js +8 -0
  471. package/dist/widgets/internals/pierre-parse/index.js.map +1 -0
  472. package/dist/widgets/internals/pierre-parse/parseDiffFromFile.d.ts +15 -0
  473. package/dist/widgets/internals/pierre-parse/parseDiffFromFile.d.ts.map +1 -0
  474. package/dist/widgets/internals/pierre-parse/parseDiffFromFile.js +39 -0
  475. package/dist/widgets/internals/pierre-parse/parseDiffFromFile.js.map +1 -0
  476. package/dist/widgets/internals/pierre-parse/parsePatchFiles.d.ts +11 -0
  477. package/dist/widgets/internals/pierre-parse/parsePatchFiles.d.ts.map +1 -0
  478. package/dist/widgets/internals/pierre-parse/parsePatchFiles.js +621 -0
  479. package/dist/widgets/internals/pierre-parse/parsePatchFiles.js.map +1 -0
  480. package/dist/widgets/internals/pierre-parse/types.d.ts +73 -0
  481. package/dist/widgets/internals/pierre-parse/types.d.ts.map +1 -0
  482. package/dist/widgets/internals/pierre-parse/types.js +7 -0
  483. package/dist/widgets/internals/pierre-parse/types.js.map +1 -0
  484. package/dist/widgets/internals/syntax.d.ts +55 -0
  485. package/dist/widgets/internals/syntax.d.ts.map +1 -0
  486. package/dist/widgets/internals/syntax.js +261 -0
  487. package/dist/widgets/internals/syntax.js.map +1 -0
  488. package/dist/widgets/markdown.d.ts +14 -0
  489. package/dist/widgets/markdown.d.ts.map +1 -0
  490. package/dist/widgets/markdown.js +9 -0
  491. package/dist/widgets/markdown.js.map +1 -0
  492. package/dist/widgets/shadow-stream.d.ts +88 -0
  493. package/dist/widgets/shadow-stream.d.ts.map +1 -0
  494. package/dist/widgets/shadow-stream.js +359 -0
  495. package/dist/widgets/shadow-stream.js.map +1 -0
  496. package/dist/widgets/speech.d.ts +36 -0
  497. package/dist/widgets/speech.d.ts.map +1 -0
  498. package/dist/widgets/speech.js +238 -0
  499. package/dist/widgets/speech.js.map +1 -0
  500. package/dist/widgets/stream-birth.d.ts +13 -0
  501. package/dist/widgets/stream-birth.d.ts.map +1 -0
  502. package/dist/widgets/stream-birth.js +70 -0
  503. package/dist/widgets/stream-birth.js.map +1 -0
  504. package/dist/widgets/syntax-boot.d.ts +25 -0
  505. package/dist/widgets/syntax-boot.d.ts.map +1 -0
  506. package/dist/widgets/syntax-boot.js +181 -0
  507. package/dist/widgets/syntax-boot.js.map +1 -0
  508. package/dist/widgets/text.d.ts +16 -0
  509. package/dist/widgets/text.d.ts.map +1 -0
  510. package/dist/widgets/text.js +14 -0
  511. package/dist/widgets/text.js.map +1 -0
  512. package/dist/widgets/transcript.d.ts +44 -0
  513. package/dist/widgets/transcript.d.ts.map +1 -0
  514. package/dist/widgets/transcript.js +106 -0
  515. package/dist/widgets/transcript.js.map +1 -0
  516. package/doom.vert +1840 -0
  517. package/fonts/DejaVuSans.ttf +0 -0
  518. package/fonts/DejaVuSansMono.ttf +0 -0
  519. package/fonts/LICENSE-DejaVu.txt +187 -0
  520. package/fonts/README.md +6 -0
  521. package/gradient.vert +75 -0
  522. package/package.json +147 -3
@@ -0,0 +1,1080 @@
1
+ /**
2
+ * ChromeFrame — special layout strategy for boxed prompt chrome.
3
+ *
4
+ * Same pattern as Indication: **one lineage** for measure, place, paint, HTML.
5
+ * Not flex assembly. Outer width is fixed; edges always span it; body sides
6
+ * track bodyH. Multi-role edge segments (progress rail, hint rule) are first-class.
7
+ *
8
+ * Geometry law:
9
+ * outerW = explicit width (clamped to alloc)
10
+ * textW = outerW - 4 // │ + mark + gap + │
11
+ * bodyH = wrap(draft, textW, pre-wrap).length (≥1)
12
+ * totalH = bodyH + 2 // top + bottom edges
13
+ * body cells: │ · text… │ (mark cell: space, picker `›`, or a counter)
14
+ * The line above the draft is one chrome rule (shortcuts left / annotation
15
+ * right). The hint is flex:0 — keys, colons, actions, and ` · ` take
16
+ * their intrinsic width. Only the annotation (filename) shrinks. If the
17
+ * hint itself overflows the band, trailing bindings drop as whole units.
18
+ * Solo frame fuses that into ╭╮. A stacked frame (joinBottom) splits:
19
+ * annotation stays on ╭╮; shortcuts ride the ├┤ T-join, with optional
20
+ * joinAnnotation on that same rule's right (session title / above-input).
21
+ * No annotation → stacked ╭╮ stays plain (slash catalog).
22
+ * Occupied right-rail slots (annotation, status) sit a space plus one
23
+ * contour cell off the corner — occupied rims end ` ─╮` / ` ─╯`.
24
+ * body hit = **text column only** (not side bars / mark).
25
+ * Selection/copy/contain use this rect — borders are chrome, not content.
26
+ * Caret park reads y/h from the same hit; col is content-relative.
27
+ */
28
+ import { formatContextOccupancy, formatHeldStatus, formatHeldStatusFit, quotaLive, } from "./live_paint.js";
29
+ import { markdownInlineSegs } from "./markdown.js";
30
+ import { paintHotkeyChord, revealHotkeys } from "./paint-hotkey.js";
31
+ import { wrapText } from "./text.js";
32
+ import { FgP, fgProgress } from "../lexicon/index.js";
33
+ import { defaultMeasure } from "../measure/index.js";
34
+ export const CHROME_FRAME_CHROME_ROWS = 2;
35
+ /** Mark cell default — empty. Picker selection paints `›` via bodyGlyphs. */
36
+ export const CHROME_FRAME_DEFAULT_GLYPH = " ";
37
+ /** │ + mark + gap + │ — subtracted from outerW to get the draft column. */
38
+ export const CHROME_FRAME_BODY_CHROME = 4;
39
+ /** Default fill hue — contour, not muted. Chroma is warning tint only. */
40
+ export const CHROME_FRAME_DEFAULT_PROGRESS_ROLE = "foreground";
41
+ /** Remaining fraction where the fill starts mixing into warning. */
42
+ export const CHROME_FRAME_DEFAULT_PROGRESS_GLOW_AT = 0.75;
43
+ /** Hot hue mixed in as remaining drops below {@link CHROME_FRAME_DEFAULT_PROGRESS_GLOW_AT}. */
44
+ export const CHROME_FRAME_PROGRESS_GLOW_ROLE = "warning";
45
+ /** Space + contour cell between a right-rail slot (annotation / status) and ╮/╯. */
46
+ const RIGHT_SLOT_PAD = " ─";
47
+ /**
48
+ * Rounded box-drawing corners (Grok Build / Claude Code prompt chrome).
49
+ * Unicode light arcs — not square `┌┐└┘`.
50
+ * ╭ ╮ U+256D / U+256E
51
+ * ╰ ╯ U+2570 / U+256F
52
+ * (Confirmed in grok binary prompt glyph table: `┌┐└┘╭╮╰╯`.)
53
+ */
54
+ export const CHROME_FRAME_CORNERS = {
55
+ tl: "╭",
56
+ tr: "╮",
57
+ bl: "╰",
58
+ br: "╯",
59
+ };
60
+ /** T-junction corners when stacking chrome frames (spotlight above input). */
61
+ export const CHROME_FRAME_JOIN = {
62
+ left: "├",
63
+ right: "┤",
64
+ };
65
+ function clamp01(n) {
66
+ if (!Number.isFinite(n))
67
+ return 0;
68
+ return Math.max(0, Math.min(1, n));
69
+ }
70
+ function measure(text) {
71
+ return defaultMeasure(text);
72
+ }
73
+ /** Draft content width inside `│ · text │` (mark + gap + sides). */
74
+ export function chromeFrameTextWidth(outerW) {
75
+ return Math.max(1, outerW - CHROME_FRAME_BODY_CHROME);
76
+ }
77
+ /** Columns from body left edge to the first text cell: `│ · ` → 3. */
78
+ export function chromeFrameTextInset() {
79
+ return CHROME_FRAME_BODY_CHROME - 1;
80
+ }
81
+ /** Text column width inside `│ · text │`. */
82
+ export function chromeFrameContentWidth(outerW) {
83
+ return chromeFrameTextWidth(outerW);
84
+ }
85
+ export function chromeFrameBodyLines(draft, outerW, placeholder) {
86
+ const w = chromeFrameTextWidth(outerW);
87
+ if (draft.length === 0) {
88
+ const ph = (placeholder ?? "").trimEnd();
89
+ if (ph.length > 0) {
90
+ const lines = wrapText(ph, {
91
+ width: w,
92
+ whiteSpace: "pre-wrap",
93
+ measure: defaultMeasure,
94
+ });
95
+ return lines.length > 0 ? lines : [" "];
96
+ }
97
+ return [" "];
98
+ }
99
+ const lines = wrapText(draft, {
100
+ width: w,
101
+ whiteSpace: "pre-wrap",
102
+ measure: defaultMeasure,
103
+ });
104
+ return lines.length > 0 ? lines : [" "];
105
+ }
106
+ /**
107
+ * True when the frame is showing empty-state placeholder chrome — body text
108
+ * is not real draft content and must not participate in text selection/copy
109
+ * (browser `<input placeholder>` model).
110
+ */
111
+ export function isChromeFrameShowingPlaceholder(node) {
112
+ if (node.placeholderMode === true)
113
+ return true;
114
+ const draft = node.speculativeDraft ?? node.draft ?? "";
115
+ if (draft.length > 0)
116
+ return false;
117
+ return !!(node.placeholder && node.placeholder.length > 0);
118
+ }
119
+ /**
120
+ * Total painted height = body + top chrome (unless omitted) + bottom chrome.
121
+ */
122
+ export function chromeFrameTotalHeight(bodyH, opts) {
123
+ const chrome = opts?.omitTop ? 1 : CHROME_FRAME_CHROME_ROWS;
124
+ return Math.max(1, bodyH) + chrome;
125
+ }
126
+ /** True when shortcuts or annotation should ride the line above the draft. */
127
+ export function chromeFrameHasHint(node) {
128
+ if ((node.hotkeys?.length ?? 0) > 0)
129
+ return true;
130
+ if ((node.annotation ?? "").trim().length > 0)
131
+ return true;
132
+ return (node.joinAnnotation ?? "").trim().length > 0;
133
+ }
134
+ /**
135
+ * Partition a bar budget into one fill + remainder. Partial cell is
136
+ * continuous in [0,1) so present can ease without snapping.
137
+ */
138
+ export function progressFillSegments(budget, ratio) {
139
+ const total = Math.max(0, Math.floor(budget));
140
+ if (total <= 0) {
141
+ return { full: 0, frac: 0, rest: 0, total: 0 };
142
+ }
143
+ const usedExact = clamp01(ratio) * total;
144
+ let full = Math.floor(usedExact + 1e-9);
145
+ let frac = usedExact - full;
146
+ if (frac < 1e-6) {
147
+ frac = 0;
148
+ }
149
+ else if (frac > 1 - 1e-6) {
150
+ full = Math.min(total, full + 1);
151
+ frac = 0;
152
+ }
153
+ full = Math.min(total, full);
154
+ const used = full + (frac > 0 ? 1 : 0);
155
+ return { full, frac, rest: Math.max(0, total - used), total };
156
+ }
157
+ /**
158
+ * Ramp along the active run: t=0 is fully fused into the contour (p=0),
159
+ * t=1 is primary against the status chips. Prominence, not lightness —
160
+ * on light ground the loud end is darker. Hue stays contour until
161
+ * warning tint starts; no extra chroma on the fill role itself.
162
+ */
163
+ export function progressRampProminence(t) {
164
+ return FgP.primary * clamp01(t);
165
+ }
166
+ /**
167
+ * Warning chroma for remaining-fill. 0 at/above `glowAt` remaining,
168
+ * 1 at empty runway. `glowAt` is the remaining fraction where orange starts.
169
+ */
170
+ export function progressGlowTint(progress, glowAt) {
171
+ const at = clamp01(glowAt);
172
+ if (!(at > 0))
173
+ return 0;
174
+ const remaining = clamp01(progress);
175
+ if (remaining >= at)
176
+ return 0;
177
+ return (at - remaining) / at;
178
+ }
179
+ /** Build a Style from role + branded FG prominence (render boundary). */
180
+ function fgStyle(role, p, opts = {}) {
181
+ return {
182
+ role,
183
+ prominence: p,
184
+ dim: opts.dim,
185
+ bold: opts.bold,
186
+ };
187
+ }
188
+ export function measureChromeFrame(node, maxW, maxH) {
189
+ const outerW = Math.max(8, Math.min(maxW, Math.floor(node.width) || maxW));
190
+ const glyph = node.glyph && node.glyph.length > 0 ? node.glyph.slice(0, 2) : CHROME_FRAME_DEFAULT_GLYPH;
191
+ const source = chromeFramePaintSource(node);
192
+ const bodyLines = node.bodySegRows && node.bodySegRows.length > 0
193
+ ? node.bodySegRows.map(() => " ")
194
+ : isChromeFrameShowingPlaceholder(node)
195
+ ? chromeFrameBodyLines("", outerW, node.placeholder)
196
+ : chromeFramePaintBodyLines(source.draft, source.completion, outerW).map((line) => line.text);
197
+ const bodyH = Math.max(1, bodyLines.length);
198
+ const totalH = Math.min(maxH, chromeFrameTotalHeight(bodyH, { omitTop: node.omitTop === true }));
199
+ // if height clamped, still report true body lines for paint clip
200
+ return {
201
+ outerW,
202
+ textW: chromeFrameTextWidth(outerW),
203
+ bodyLines,
204
+ bodyH,
205
+ totalH: Math.max(1, totalH),
206
+ glyph,
207
+ };
208
+ }
209
+ function padDash(n) {
210
+ return n > 0 ? "─".repeat(n) : "";
211
+ }
212
+ /**
213
+ * Frame contour (top rule, sides, corners, unfilled rail, unstyled status).
214
+ * Furniture weight is ghost unless the frame is the selection (primary).
215
+ * Hue follows {@link boxContour}. Progress fill uses its own role and
216
+ * fuses into this contour (gradient hint).
217
+ */
218
+ function boxContour(role, prominence = FgP.ghost) {
219
+ return fgStyle(role && role.length > 0 ? role : "foreground", prominence);
220
+ }
221
+ function contourProminenceOf(node) {
222
+ return node.selected === true ? FgP.primary : FgP.ghost;
223
+ }
224
+ const contour = boxContour();
225
+ /** Hotkey chord — primary, no chroma. */
226
+ const shortcutKey = fgStyle("foreground", FgP.primary);
227
+ /** Hotkey action — same voice as annotation / status, not the contour. */
228
+ const shortcutAction = fgStyle("foreground", FgP.ghost);
229
+ /** Draft body — primary, roman. */
230
+ const bodyStyle = fgStyle("foreground", FgP.primary);
231
+ /** Empty-state placeholder — muted, never selected. */
232
+ const placeholderStyle = fgStyle("muted", FgP.ghost);
233
+ /** Autocomplete remainder — same voice as placeholder; not draft. */
234
+ const completionStyle = placeholderStyle;
235
+ /**
236
+ * Draft plus optional dim remainder. Completion is paint-only: it hangs off
237
+ * the last draft line and MUST NOT reflow typed text (caret/click wrap draft
238
+ * alone). Wrapping `draft+completion` as one string breaks inside a
239
+ * multi-word prefix (`/connect LM` + ` Studio` at width 11 → `/connect` /
240
+ * `LM Studio`).
241
+ */
242
+ function chromeFramePaintSource(node) {
243
+ const draft = node.speculativeDraft ?? node.draft ?? "";
244
+ const completion = draft.length === 0 ? "" : (node.completion ?? "").length > 0 ? node.completion : "";
245
+ return { draft, completion, draftLength: draft.length };
246
+ }
247
+ /** Visual body lines of draft, then remainder overflow that does not split them. */
248
+ function chromeFramePaintBodyLines(draft, completion, outerW) {
249
+ const draftLines = chromeFrameBodyLinesWithStarts(draft, outerW);
250
+ if (completion.length === 0)
251
+ return draftLines;
252
+ const textW = chromeFrameTextWidth(outerW);
253
+ const last = draftLines.at(-1);
254
+ const wrapped = wrapText(last.text + completion, {
255
+ width: textW,
256
+ whiteSpace: "pre-wrap",
257
+ measure: defaultMeasure,
258
+ });
259
+ const head = wrapped[0] ?? "";
260
+ if (head.startsWith(last.text)) {
261
+ const out = draftLines.slice(0, -1);
262
+ let pos = last.start;
263
+ for (const line of wrapped) {
264
+ out.push({ text: line, start: pos });
265
+ pos += line.length;
266
+ }
267
+ return out.length > 0 ? out : draftLines;
268
+ }
269
+ // Combined wrap would split the last draft line. Keep it; overflow remainder.
270
+ let overflow = completion;
271
+ let skip = 0;
272
+ if (overflow.startsWith(" ")) {
273
+ overflow = overflow.slice(1);
274
+ skip = 1;
275
+ }
276
+ if (overflow.length === 0)
277
+ return draftLines;
278
+ const extra = wrapText(overflow, {
279
+ width: textW,
280
+ whiteSpace: "pre-wrap",
281
+ measure: defaultMeasure,
282
+ });
283
+ const out = [...draftLines];
284
+ let pos = last.start + last.text.length + skip;
285
+ for (const line of extra) {
286
+ if (line.length === 0)
287
+ continue;
288
+ out.push({ text: line, start: pos });
289
+ pos += line.length;
290
+ }
291
+ return out;
292
+ }
293
+ /** Picker mark (`›`) — primary. Draft mark is a space (no chevron). */
294
+ const glyphStyle = fgStyle("foreground", FgP.primary, { bold: true });
295
+ /** Counters and other technical marks in the same cell — furniture. */
296
+ const counterStyle = fgStyle("muted", FgP.ghost);
297
+ function markCellStyle(mark) {
298
+ return mark === "›" ? glyphStyle : counterStyle;
299
+ }
300
+ function ellipsizeTo(text, maxW) {
301
+ if (maxW <= 0)
302
+ return "";
303
+ if (measure(text) <= maxW)
304
+ return text;
305
+ if (maxW === 1)
306
+ return "…";
307
+ let h = text;
308
+ while (measure(`${h}…`) > maxW && h.length > 0)
309
+ h = h.slice(0, -1);
310
+ return h.length > 0 ? `${h}…` : "…";
311
+ }
312
+ /**
313
+ * Furniture clip: 3-cell prefix + … + tail.
314
+ * Fault annotations keep {@link ellipsizeTo} (prefix + …).
315
+ */
316
+ function ellipsizeAffixTo(text, maxW) {
317
+ if (maxW <= 0)
318
+ return "";
319
+ if (measure(text) <= maxW)
320
+ return text;
321
+ if (maxW === 1)
322
+ return "…";
323
+ let prefix = text;
324
+ while (measure(prefix) > 3 && prefix.length > 0)
325
+ prefix = prefix.slice(0, -1);
326
+ if (prefix.length === 0) {
327
+ let t = text;
328
+ while (measure(`…${t}`) > maxW && t.length > 0)
329
+ t = t.slice(1);
330
+ return t.length > 0 ? `…${t}` : "…";
331
+ }
332
+ const head = `${prefix}…`;
333
+ const headW = measure(head);
334
+ if (headW > maxW) {
335
+ let h = prefix;
336
+ while (measure(`${h}…`) > maxW && h.length > 0)
337
+ h = h.slice(0, -1);
338
+ return h.length > 0 ? `${h}…` : "…";
339
+ }
340
+ if (headW === maxW)
341
+ return head;
342
+ const tailBudget = maxW - headW;
343
+ let tail = text;
344
+ while (measure(tail) > tailBudget && tail.length > 0)
345
+ tail = tail.slice(1);
346
+ const tailAt = text.length - tail.length;
347
+ if (tailAt < prefix.length) {
348
+ tail = text.slice(prefix.length);
349
+ while (measure(tail) > tailBudget && tail.length > 0)
350
+ tail = tail.slice(1);
351
+ }
352
+ return tail.length > 0 ? `${head}${tail}` : head;
353
+ }
354
+ function segsWidth(segs) {
355
+ let n = 0;
356
+ for (const s of segs)
357
+ n += measure(s.text);
358
+ return n;
359
+ }
360
+ function hintPieces(hotkeys) {
361
+ const out = [];
362
+ for (const hotkey of hotkeys) {
363
+ const key = hotkey.key.trim();
364
+ if (key.length === 0)
365
+ continue;
366
+ if (out.length > 0)
367
+ out.push({ text: " · ", style: contour, hint: "sep" });
368
+ const action = hotkey.action.trim();
369
+ out.push({ text: paintHotkeyChord(key), style: shortcutKey, hint: "key" });
370
+ if (action.length === 0)
371
+ continue;
372
+ out.push({ text: ": ", style: shortcutKey, hint: "colon" }, { text: action, style: shortcutAction, hint: "action" });
373
+ }
374
+ return out;
375
+ }
376
+ function emitHintPieces(pieces) {
377
+ return pieces.map(({ text, style }) => ({ text, style }));
378
+ }
379
+ /** Drop trailing ` · key: action` units until the hint fits. Never clip a binding. */
380
+ function dropTrailingHintBindings(pieces, maxW) {
381
+ let next = [...pieces];
382
+ while (next.length > 0 && segsWidth(next) > maxW) {
383
+ let cut = -1;
384
+ for (let i = next.length - 1; i >= 0; i--) {
385
+ if (next[i].hint === "sep") {
386
+ cut = i;
387
+ break;
388
+ }
389
+ }
390
+ if (cut < 0) {
391
+ next = [];
392
+ break;
393
+ }
394
+ next = next.slice(0, cut);
395
+ }
396
+ return next;
397
+ }
398
+ function fitHintAndAnnotation(hotkeys, right, budget, annKeep) {
399
+ const pieces = hotkeys.length > 0 ? hintPieces(hotkeys) : [];
400
+ const rightWant = segsWidth(right);
401
+ if (pieces.length === 0) {
402
+ return {
403
+ left: [],
404
+ right: rightWant <= budget ? right : trimSegsTo(right, budget, { keep: annKeep }),
405
+ };
406
+ }
407
+ const left = emitHintPieces(dropTrailingHintBindings(pieces, budget));
408
+ const annW = Math.max(0, budget - segsWidth(left));
409
+ const rightFit = rightWant <= annW ? right : trimSegsTo(right, annW, { keep: annKeep });
410
+ return { left, right: rightFit };
411
+ }
412
+ function trimSegsTo(segs, maxW, opts) {
413
+ if (maxW <= 0)
414
+ return [];
415
+ const clip = opts?.keep === "affix" ? ellipsizeAffixTo : ellipsizeTo;
416
+ const out = [];
417
+ let used = 0;
418
+ for (const s of segs) {
419
+ const tw = measure(s.text);
420
+ if (used + tw <= maxW) {
421
+ out.push(s);
422
+ used += tw;
423
+ continue;
424
+ }
425
+ const room = maxW - used;
426
+ if (room <= 0)
427
+ break;
428
+ const clipped = clip(s.text, room);
429
+ if (clipped.length > 0)
430
+ out.push({ ...s, text: clipped });
431
+ break;
432
+ }
433
+ return out;
434
+ }
435
+ /**
436
+ * One full-width chrome rule: shortcuts left, annotation right, dashes between.
437
+ * Solo frame uses ╭╮. Stacked: call twice — annotation on ╭╮, shortcuts on ├┤.
438
+ */
439
+ export function chromeFrameTopSegs(outerW, hotkeys, opts) {
440
+ const w = Math.max(4, outerW);
441
+ const box = boxContour(opts?.contourRole, opts?.contourProminence);
442
+ const hint = revealHotkeys(hotkeys ?? [], { modHeld: opts?.modHeld === true });
443
+ const hasHint = hint.length > 0;
444
+ const L = opts?.join
445
+ ? CHROME_FRAME_JOIN.left
446
+ : opts?.bottom === true
447
+ ? CHROME_FRAME_CORNERS.bl
448
+ : CHROME_FRAME_CORNERS.tl;
449
+ const R = opts?.join
450
+ ? CHROME_FRAME_JOIN.right
451
+ : opts?.bottom === true
452
+ ? CHROME_FRAME_CORNERS.br
453
+ : CHROME_FRAME_CORNERS.tr;
454
+ const fault = opts?.annotationRole === "error" || opts?.annotationRole === "warning";
455
+ const annStyle = fgStyle(fault
456
+ ? opts.annotationRole
457
+ : opts?.annotationRole && opts.annotationRole.length > 0
458
+ ? opts.annotationRole
459
+ : "foreground", fault ? FgP.primary : FgP.ghost);
460
+ let right = opts?.annotationSegs ? opts.annotationSegs.filter((s) => s.text.length > 0) : [];
461
+ if (right.length === 0) {
462
+ const ann = (opts?.annotation ?? "").trim();
463
+ if (ann.length > 0) {
464
+ right = markdownInlineSegs(ann, annStyle).map((s) => ({
465
+ text: s.text,
466
+ // Furniture emphasis is the bright run (same voice as a hotkey chord).
467
+ // Fault annotations stay their role — do not restyle ** as primary.
468
+ style: !fault && s.style.bold === true ? { ...s.style, bold: false, prominence: FgP.primary } : s.style,
469
+ }));
470
+ }
471
+ }
472
+ const segs = [{ text: L, style: box }];
473
+ if (!hasHint && right.length === 0) {
474
+ segs.push({ text: padDash(w - 2), style: box }, { text: R, style: box });
475
+ return segs;
476
+ }
477
+ const leftPrefix = hasHint ? "─ " : "";
478
+ // Space after the dash fill; space + contour dash before the corner when occupied.
479
+ const rightPrefix = right.length > 0 ? " " : "";
480
+ const rightSuffix = right.length > 0 ? RIGHT_SLOT_PAD : "";
481
+ const trail = hasHint ? 1 : 0;
482
+ const minFill = hasHint && right.length > 0 ? 1 : 0;
483
+ const chrome = 2 + measure(leftPrefix) + trail + measure(rightPrefix) + measure(rightSuffix) + minFill;
484
+ const budget = Math.max(0, w - chrome);
485
+ const fitted = fitHintAndAnnotation(hint, right, budget, fault ? "start" : "affix");
486
+ const leftSegs = fitted.left;
487
+ const rightFit = fitted.right;
488
+ if (leftPrefix)
489
+ segs.push({ text: leftPrefix, style: box });
490
+ for (const s of leftSegs)
491
+ segs.push(s);
492
+ if (hasHint)
493
+ segs.push({ text: " ", style: box });
494
+ const used = 2 +
495
+ measure(leftPrefix) +
496
+ segsWidth(leftSegs) +
497
+ (hasHint ? 1 : 0) +
498
+ measure(rightPrefix) +
499
+ segsWidth(rightFit) +
500
+ measure(rightSuffix);
501
+ const fill = Math.max(0, w - used);
502
+ if (fill > 0)
503
+ segs.push({ text: padDash(fill), style: box });
504
+ if (rightPrefix)
505
+ segs.push({ text: rightPrefix, style: box });
506
+ for (const s of rightFit)
507
+ segs.push(s);
508
+ if (rightSuffix)
509
+ segs.push({ text: rightSuffix, style: box });
510
+ segs.push({ text: R, style: box });
511
+ return segs;
512
+ }
513
+ /** Plain bottom rule (no context bar) — optional T-join corners. */
514
+ export function chromeFramePlainBottomSegs(outerW, opts) {
515
+ const w = Math.max(4, outerW);
516
+ const box = boxContour(opts?.contourRole, opts?.contourProminence);
517
+ const L = opts?.join ? CHROME_FRAME_JOIN.left : CHROME_FRAME_CORNERS.bl;
518
+ const R = opts?.join ? CHROME_FRAME_JOIN.right : CHROME_FRAME_CORNERS.br;
519
+ return [
520
+ { text: L, style: box },
521
+ { text: padDash(w - 2), style: box },
522
+ { text: R, style: box },
523
+ ];
524
+ }
525
+ /**
526
+ * Top edge from multi-style content segs (between corners).
527
+ * Pads with contour dashes so corners stay at outerW.
528
+ */
529
+ export function chromeFrameTopFromContentSegs(outerW, content, opts) {
530
+ const w = Math.max(4, outerW);
531
+ const box = boxContour(opts?.contourRole, opts?.contourProminence);
532
+ const segs = [{ text: CHROME_FRAME_CORNERS.tl, style: box }];
533
+ let used = 2; // corners
534
+ for (const s of content) {
535
+ const tw = measure(s.text);
536
+ if (used + tw > w)
537
+ break;
538
+ segs.push(s);
539
+ used += tw;
540
+ }
541
+ const fill = Math.max(0, w - used);
542
+ if (fill > 0)
543
+ segs.push({ text: padDash(fill), style: box });
544
+ segs.push({ text: CHROME_FRAME_CORNERS.tr, style: box });
545
+ return segs;
546
+ }
547
+ function styleFromSpec(s) {
548
+ return {
549
+ role: s.role,
550
+ prominence: s.prominence,
551
+ bold: s.bold,
552
+ dim: s.dim,
553
+ italic: s.italic,
554
+ underline: s.underline,
555
+ href: s.href,
556
+ fgRgb: s.fgRgb,
557
+ };
558
+ }
559
+ function statusChipText(item) {
560
+ return (typeof item === "string" ? item : item.text).trim();
561
+ }
562
+ function statusChipStyle(item, box) {
563
+ if (typeof item === "string")
564
+ return contour;
565
+ if (item.role && item.role.length > 0) {
566
+ return { role: item.role, prominence: item.prominence ?? FgP.secondary };
567
+ }
568
+ return box;
569
+ }
570
+ function normalizeStatusItems(items) {
571
+ return (items ?? []).filter((item) => statusChipText(item).length > 0);
572
+ }
573
+ /** Persist-mod replaces furniture chips with occupancy + quota; signal chips stay. */
574
+ function statusRailOf(opts, maxColumns) {
575
+ const base = normalizeStatusItems(opts.statusItems);
576
+ if (opts.modHeld !== true)
577
+ return { items: base };
578
+ const windows = (opts.quotaWindows ?? []).filter((window) => Number.isFinite(window.remainingPercent));
579
+ const prefix = formatContextOccupancy(opts.contextUsed ?? 0, opts.contextLimit ?? 0);
580
+ const nowMs = opts.nowMs ?? Date.now();
581
+ const full = formatHeldStatus(prefix, windows, nowMs);
582
+ const text = maxColumns === undefined ? full : formatHeldStatusFit(prefix, windows, nowMs, maxColumns, measure);
583
+ if (text === "")
584
+ return { items: base };
585
+ const signals = base.filter((item) => typeof item !== "string");
586
+ const occupancyOnly = text !== full;
587
+ return {
588
+ items: [text, ...signals],
589
+ // Live ticks rebuild the full hint and would paint over a fitted chip.
590
+ live: windows.length > 0 && !occupancyOnly ? quotaLive(windows, { prefix }) : undefined,
591
+ };
592
+ }
593
+ /** Joined status for measure / hit geometry. Leading space matches paint. */
594
+ export function statusRightText(opts) {
595
+ const items = statusRailOf(opts).items.map(statusChipText);
596
+ if (items.length > 0)
597
+ return ` ${items.join(" · ")}`;
598
+ return "";
599
+ }
600
+ /** Right-rail chips. Drops leftmost furniture first so a signal chip survives clip. */
601
+ function statusRightSegs(opts, box, maxW) {
602
+ if (maxW <= 0)
603
+ return [];
604
+ // Leading space is part of the painted rail, so the chip text has one less column.
605
+ const rail = statusRailOf(opts, Math.max(0, maxW - 1));
606
+ let chips = rail.items;
607
+ if (chips.length === 0)
608
+ return [];
609
+ const build = (list) => {
610
+ const segs = [{ text: " ", style: box }];
611
+ for (const [i, element] of list.entries()) {
612
+ if (i > 0)
613
+ segs.push({ text: " · ", style: box });
614
+ const chip = element;
615
+ const seg = {
616
+ text: statusChipText(chip),
617
+ style: statusChipStyle(chip, box),
618
+ };
619
+ if (rail.live !== undefined && typeof chip === "string" && i === 0)
620
+ seg.live = rail.live;
621
+ segs.push(seg);
622
+ }
623
+ return segs;
624
+ };
625
+ let segs = build(chips);
626
+ while (segsWidth(segs) > maxW && chips.length > 1) {
627
+ chips = chips.slice(1);
628
+ segs = build(chips);
629
+ }
630
+ if (segsWidth(segs) > maxW) {
631
+ const clipped = ellipsizeTo(statusRightText({ statusItems: chips }), maxW);
632
+ return clipped.length > 0 ? [{ text: clipped, style: box }] : [];
633
+ }
634
+ return segs;
635
+ }
636
+ /** One ─ per fill cell, prominence ramping toward the status edge. */
637
+ function progressRampSegs(fill, role, fuseRole = "foreground", glow = 0) {
638
+ const n = fill.full + (fill.frac > 0 ? 1 : 0);
639
+ if (n <= 0)
640
+ return [];
641
+ const out = [];
642
+ const tint = Math.max(glow, 0);
643
+ for (let i = 0; i < n; i++) {
644
+ const t = n === 1 ? 1 : i / (n - 1);
645
+ const tt = i === 0 && fill.frac > 0 ? t * fill.frac : t;
646
+ out.push({
647
+ text: "─",
648
+ style: {
649
+ role,
650
+ prominence: progressRampProminence(tt),
651
+ fuseRole,
652
+ fuseProminence: FgP.ghost,
653
+ ...(tint > 0 ? { tintRole: CHROME_FRAME_PROGRESS_GLOW_ROLE, tint } : {}),
654
+ },
655
+ });
656
+ }
657
+ return out;
658
+ }
659
+ /** Bottom edge: optional one-hue progress ramp + status, spanning `outerW`. */
660
+ export function chromeFrameBottomSegs(outerW, opts) {
661
+ const w = Math.max(4, outerW);
662
+ const box = boxContour(opts.contourRole, opts.contourProminence);
663
+ if (opts.plain) {
664
+ return chromeFramePlainBottomSegs(w, {
665
+ join: opts.join,
666
+ contourRole: opts.contourRole,
667
+ contourProminence: opts.contourProminence,
668
+ });
669
+ }
670
+ const boxed = opts.contourRole != null && opts.contourRole.length > 0;
671
+ const raw = opts.progress;
672
+ // Omit progress → dashes. `progress ?? 0` invents a fill on a plain rule.
673
+ const hasProgress = !boxed && typeof raw === "number" && Number.isFinite(raw);
674
+ const bl = opts.join ? CHROME_FRAME_JOIN.left : CHROME_FRAME_CORNERS.bl;
675
+ const br = opts.join ? CHROME_FRAME_JOIN.right : CHROME_FRAME_CORNERS.br;
676
+ const minRail = hasProgress ? 6 : 0;
677
+ const reserve = measure(RIGHT_SLOT_PAD);
678
+ const rightSegs = statusRightSegs(opts, box, Math.max(0, w - 2 - minRail - reserve));
679
+ const rightW = segsWidth(rightSegs);
680
+ const trailPad = rightW > 0 ? measure(RIGHT_SLOT_PAD) : 0;
681
+ const segs = [{ text: bl, style: box }];
682
+ if (!hasProgress) {
683
+ const mid = Math.max(0, w - 2 - rightW - trailPad);
684
+ if (mid > 0)
685
+ segs.push({ text: padDash(mid), style: box });
686
+ for (const s of rightSegs)
687
+ segs.push(s);
688
+ if (trailPad > 0)
689
+ segs.push({ text: RIGHT_SLOT_PAD, style: box });
690
+ segs.push({ text: br, style: box });
691
+ return segs;
692
+ }
693
+ const ratio = clamp01(raw);
694
+ const role = opts.progressRole && opts.progressRole.length > 0 ? opts.progressRole : CHROME_FRAME_DEFAULT_PROGRESS_ROLE;
695
+ const fillBudget = Math.max(0, w - 2 - rightW - trailPad);
696
+ const fill = progressFillSegments(fillBudget, ratio);
697
+ const fuseRole = opts.contourRole && opts.contourRole.length > 0 ? opts.contourRole : "foreground";
698
+ const glowAt = typeof opts.progressGlowAt === "number" && Number.isFinite(opts.progressGlowAt)
699
+ ? opts.progressGlowAt
700
+ : CHROME_FRAME_DEFAULT_PROGRESS_GLOW_AT;
701
+ const ramp = progressRampSegs(fill, role, fuseRole, progressGlowTint(ratio, glowAt));
702
+ if (fill.rest > 0)
703
+ segs.push({ text: padDash(fill.rest), style: box });
704
+ const painted = fill.full + (fill.frac > 0 ? 1 : 0) + fill.rest + rightW + trailPad + 2;
705
+ if (painted < w) {
706
+ segs.push({ text: padDash(w - painted), style: box });
707
+ }
708
+ for (const s of ramp)
709
+ segs.push(s);
710
+ for (const s of rightSegs)
711
+ segs.push(s);
712
+ if (trailPad > 0)
713
+ segs.push({ text: RIGHT_SLOT_PAD, style: box });
714
+ segs.push({ text: br, style: box });
715
+ return segs;
716
+ }
717
+ /** Right │ — contour hue; coverage ramps contour weight→primary. */
718
+ function rightBarStyle(t, contourRole, prominence = FgP.ghost) {
719
+ const box = boxContour(contourRole, prominence);
720
+ if (t === undefined)
721
+ return box;
722
+ return {
723
+ role: contourRole && contourRole.length > 0 ? contourRole : "foreground",
724
+ prominence: fgProgress(prominence, FgP.primary, t),
725
+ };
726
+ }
727
+ /** One body row: `│ · text…(padded) │` — always `outerW` cells. */
728
+ export function chromeFrameBodyRowSegs(line, row, outerW, glyph, opts) {
729
+ const box = boxContour(opts?.contourRole, opts?.contourProminence);
730
+ const textW = chromeFrameTextWidth(outerW);
731
+ let body = line;
732
+ while (measure(body) > textW && body.length > 0)
733
+ body = body.slice(0, -1);
734
+ if (body.length === 0)
735
+ body = " ";
736
+ const pad = Math.max(0, textW - measure(body));
737
+ // Pad with spaces in the segment string — paint is text ops, not flex;
738
+ // spaces are literal cells (pre-sized), so right │ is always at outerW-1.
739
+ const textStyle = opts?.placeholder ? placeholderStyle : bodyStyle;
740
+ const split = !opts?.placeholder &&
741
+ opts?.lineStart !== undefined &&
742
+ (opts.draftLength !== undefined || (opts.selA !== undefined && opts.selB !== undefined && opts.selA < opts.selB));
743
+ const textSegs = split
744
+ ? splitBodyRuns(body, opts.lineStart, {
745
+ selA: opts.selA,
746
+ selB: opts.selB,
747
+ draftLength: opts.draftLength,
748
+ draftStyle: textStyle,
749
+ pad,
750
+ })
751
+ : [{ text: body + (pad > 0 ? " ".repeat(pad) : ""), style: textStyle }];
752
+ const mark = row === 0 ? glyph : " ";
753
+ const marked = mark.trim().length > 0;
754
+ return [
755
+ { text: "│", style: box },
756
+ { text: marked ? mark : " ", style: marked ? markCellStyle(mark) : {} },
757
+ { text: " ", style: {} },
758
+ ...textSegs,
759
+ { text: "│", style: rightBarStyle(opts?.rightCoverage, opts?.contourRole, opts?.contourProminence) },
760
+ ];
761
+ }
762
+ /** Split a visual body line into draft / selected / completion runs. */
763
+ function splitBodyRuns(body, lineStart, opts) {
764
+ const segs = [];
765
+ let i = 0;
766
+ const n = body.length;
767
+ while (i < n) {
768
+ const kind = bodyRunKind(lineStart + i, opts);
769
+ let j = i + 1;
770
+ while (j < n && bodyRunKind(lineStart + j, opts) === kind)
771
+ j++;
772
+ segs.push({
773
+ text: body.slice(i, j),
774
+ style: kind === "completion"
775
+ ? completionStyle
776
+ : kind === "sel"
777
+ ? { ...opts.draftStyle, selected: true }
778
+ : opts.draftStyle,
779
+ });
780
+ i = j;
781
+ }
782
+ if (opts.pad > 0)
783
+ segs.push({ text: " ".repeat(opts.pad), style: opts.draftStyle });
784
+ if (segs.length === 0)
785
+ segs.push({ text: " ", style: opts.draftStyle });
786
+ return segs;
787
+ }
788
+ function bodyRunKind(abs, opts) {
789
+ if (opts.draftLength !== undefined && abs >= opts.draftLength)
790
+ return "completion";
791
+ if (opts.selA !== undefined && opts.selB !== undefined && abs >= opts.selA && abs < opts.selB) {
792
+ return "sel";
793
+ }
794
+ return "draft";
795
+ }
796
+ /**
797
+ * Visual body lines of a draft with absolute start offsets into the draft.
798
+ * Matches {@link chromeFrameBodyLines} partition for pre-wrap soft wrap.
799
+ */
800
+ export function chromeFrameBodyLinesWithStarts(draft, outerW) {
801
+ const w = chromeFrameTextWidth(outerW);
802
+ if (draft.length === 0)
803
+ return [{ text: " ", start: 0 }];
804
+ const hardLines = draft.split("\n");
805
+ const out = [];
806
+ let pos = 0;
807
+ for (let hi = 0; hi < hardLines.length; hi++) {
808
+ const hard = hardLines[hi];
809
+ const soft = wrapText(hard, {
810
+ width: w,
811
+ whiteSpace: "pre-wrap",
812
+ measure: defaultMeasure,
813
+ });
814
+ let hardPos = 0;
815
+ for (const line of soft) {
816
+ out.push({ text: line, start: pos + hardPos });
817
+ hardPos += line.length;
818
+ }
819
+ pos += hard.length;
820
+ if (hi < hardLines.length - 1)
821
+ pos += 1; // consumed `\n`
822
+ }
823
+ return out.length > 0 ? out : [{ text: " ", start: 0 }];
824
+ }
825
+ /**
826
+ * Body row from multi-style content segs.
827
+ *
828
+ * Aligned grid: `│ · text… │` textW = outerW − 4
829
+ * Selection marks go in `glyph` (`›` / ` `), not in text.
830
+ */
831
+ export function chromeFrameBodyFromContentSegs(content, outerW, opts = {}) {
832
+ const w = Math.max(4, outerW);
833
+ const box = boxContour(opts.contourRole, opts.contourProminence);
834
+ const contentBudget = chromeFrameTextWidth(w);
835
+ const g = (opts.glyph && opts.glyph.length > 0 ? opts.glyph : " ").slice(0, 2);
836
+ const marked = g.trim().length > 0;
837
+ const segs = [
838
+ { text: "│", style: box },
839
+ { text: marked ? g : " ", style: marked ? markCellStyle(g) : {} },
840
+ { text: " ", style: {} },
841
+ ];
842
+ let contentUsed = 0;
843
+ for (const s of content) {
844
+ const tw = measure(s.text);
845
+ if (contentUsed + tw > contentBudget)
846
+ break;
847
+ segs.push(s);
848
+ contentUsed += tw;
849
+ }
850
+ const pad = Math.max(0, contentBudget - contentUsed);
851
+ if (pad > 0)
852
+ segs.push({ text: " ".repeat(pad), style: {} });
853
+ segs.push({ text: "│", style: rightBarStyle(opts.rightCoverage, opts.contourRole, opts.contourProminence) });
854
+ return segs;
855
+ }
856
+ /**
857
+ * Resolve glyph cell for body row i.
858
+ * bodyGlyphs wins; else draft mode uses frame glyph on row 0 only.
859
+ */
860
+ export function chromeFrameRowGlyph(node, row, frameGlyph) {
861
+ if (node.bodyGlyphs && row < node.bodyGlyphs.length) {
862
+ const g = node.bodyGlyphs[row];
863
+ if (g !== undefined && g !== null) {
864
+ return g.length > 0 ? g.slice(0, 2) : " ";
865
+ }
866
+ }
867
+ if (row === 0)
868
+ return frameGlyph;
869
+ return " ";
870
+ }
871
+ /** Emit horizontal segment runs as text paint ops at (x, y). */
872
+ export function segsToPaintOps(segs, x, y, clipW) {
873
+ const ops = [];
874
+ let cx = x;
875
+ let remaining = clipW;
876
+ for (const s of segs) {
877
+ if (remaining <= 0)
878
+ break;
879
+ let t = s.text;
880
+ let tw = measure(t);
881
+ if (tw > remaining) {
882
+ // hard clip by columns
883
+ while (t.length > 0 && measure(t) > remaining)
884
+ t = t.slice(0, -1);
885
+ tw = measure(t);
886
+ }
887
+ if (t.length === 0 || tw <= 0)
888
+ continue;
889
+ ops.push(s.live === undefined
890
+ ? {
891
+ kind: "text",
892
+ rect: { x: cx, y, w: tw, h: 1 },
893
+ lines: [t],
894
+ style: s.style,
895
+ }
896
+ : {
897
+ kind: "live",
898
+ rect: { x: cx, y, w: tw, h: 1 },
899
+ style: s.style,
900
+ live: s.live,
901
+ });
902
+ cx += tw;
903
+ remaining -= tw;
904
+ }
905
+ return ops;
906
+ }
907
+ /**
908
+ * Full paint ops for a chrome_frame placed at `rect`.
909
+ *
910
+ * Row map (always full `w` cells per edge/body line):
911
+ * y+0 ╭╮ — solo: shortcuts + annotation; stacked: annotation only
912
+ * y+1..y+bodyH body (`│ text… │`)
913
+ * last bottom edge, or ├┤ T-join carrying shortcuts + joinAnnotation
914
+ */
915
+ export function chromeFramePaintOps(node, rect) {
916
+ const geom = measureChromeFrame(node, rect.w, rect.h);
917
+ const w = Math.min(rect.w, geom.outerW);
918
+ const maxRows = Math.max(1, rect.h);
919
+ const ops = [];
920
+ const omitTop = node.omitTop === true;
921
+ const joinHint = node.joinBottom === true && chromeFrameHasHint(node);
922
+ const contourP = contourProminenceOf(node);
923
+ const chromeTop = omitTop ? 0 : 1;
924
+ // Prefer keeping edges: body gets whatever remains after chrome rows.
925
+ const chromeMin = chromeTop + 1; // top(optional) + bottom
926
+ const bodyBudget = maxRows <= chromeMin ? Math.max(0, maxRows - chromeTop) : Math.min(geom.bodyLines.length, maxRows - chromeMin);
927
+ const bodyH = maxRows <= chromeTop
928
+ ? 0
929
+ : maxRows === chromeTop + 1
930
+ ? Math.min(1, geom.bodyLines.length)
931
+ : Math.max(omitTop ? 0 : 1, bodyBudget);
932
+ // top (skipped when stacked under a joinBottom panel). Shortcuts leave
933
+ // this rule for the T-join; annotation stays here when a ╭╮ exists.
934
+ // hotkeysBottom is window chrome: hints ride ╰╯, title stays on ╭╮.
935
+ const hotkeysOnTop = joinHint === false && node.hotkeysBottom !== true;
936
+ if (!omitTop) {
937
+ if (node.topSegs && node.topSegs.length > 0) {
938
+ const content = node.topSegs.map((s) => ({
939
+ text: s.text,
940
+ style: styleFromSpec(s),
941
+ }));
942
+ ops.push(...segsToPaintOps(chromeFrameTopFromContentSegs(w, content, {
943
+ contourRole: node.contourRole,
944
+ contourProminence: contourP,
945
+ }), rect.x, rect.y, w));
946
+ }
947
+ else {
948
+ ops.push(...segsToPaintOps(chromeFrameTopSegs(w, hotkeysOnTop ? node.hotkeys : null, {
949
+ join: node.joinTop === true,
950
+ annotation: node.annotation,
951
+ annotationRole: node.annotationRole,
952
+ contourRole: node.contourRole,
953
+ contourProminence: contourP,
954
+ modHeld: node.modHeld,
955
+ }), rect.x, rect.y, w));
956
+ }
957
+ }
958
+ const bodyY0 = rect.y + chromeTop;
959
+ for (let i = 0; i < bodyH; i++) {
960
+ const rightCoverage = node.bodyRightCoverage?.[i];
961
+ if (node.bodySegRows?.[i]) {
962
+ const content = node.bodySegRows[i].map((s) => ({
963
+ text: s.text,
964
+ style: styleFromSpec(s),
965
+ }));
966
+ const rowGlyph = chromeFrameRowGlyph(node, i, geom.glyph);
967
+ ops.push(...segsToPaintOps(chromeFrameBodyFromContentSegs(content, w, {
968
+ glyph: rowGlyph,
969
+ row: i,
970
+ rightCoverage,
971
+ contourRole: node.contourRole,
972
+ contourProminence: contourP,
973
+ }), rect.x, bodyY0 + i, w));
974
+ }
975
+ else {
976
+ const ph = isChromeFrameShowingPlaceholder(node);
977
+ const source = chromeFramePaintSource(node);
978
+ const withStarts = ph ? null : chromeFramePaintBodyLines(source.draft, source.completion, w);
979
+ const rowInfo = withStarts?.[i];
980
+ const line = rowInfo?.text ?? geom.bodyLines[i] ?? " ";
981
+ const cursor = node.cursor;
982
+ const mark = node.mark;
983
+ const hasSel = typeof cursor === "number" && typeof mark === "number" && mark !== cursor;
984
+ const selA = hasSel ? Math.min(cursor, mark) : undefined;
985
+ const selB = hasSel ? Math.max(cursor, mark) : undefined;
986
+ ops.push(...segsToPaintOps(chromeFrameBodyRowSegs(line, i, w, geom.glyph, {
987
+ placeholder: ph,
988
+ lineStart: rowInfo?.start,
989
+ selA,
990
+ selB,
991
+ draftLength: ph ? undefined : source.draftLength,
992
+ rightCoverage,
993
+ contourRole: node.contourRole,
994
+ contourProminence: contourP,
995
+ }), rect.x, bodyY0 + i, w));
996
+ }
997
+ }
998
+ // bottom (when room). A stacked picker paints shortcuts on this T-join —
999
+ // the line above the draft — not on ╭╮. Annotation stays on ╭╮;
1000
+ // joinAnnotation is the T-join's right-rail (title above the input).
1001
+ const botY = bodyY0 + bodyH;
1002
+ let progressHit = { x: rect.x + 1, y: botY, w: Math.max(0, w - 2), h: 1 };
1003
+ if (botY < rect.y + maxRows) {
1004
+ const bottomSegs = joinHint
1005
+ ? chromeFrameTopSegs(w, node.hotkeys, {
1006
+ join: true,
1007
+ annotation: node.joinAnnotation,
1008
+ annotationRole: node.joinAnnotationRole,
1009
+ contourRole: node.contourRole,
1010
+ contourProminence: contourP,
1011
+ modHeld: node.modHeld,
1012
+ })
1013
+ : node.hotkeysBottom === true
1014
+ ? chromeFrameTopSegs(w, node.hotkeys, {
1015
+ bottom: true,
1016
+ contourRole: node.contourRole,
1017
+ contourProminence: contourP,
1018
+ modHeld: node.modHeld,
1019
+ })
1020
+ : chromeFrameBottomSegs(w, {
1021
+ progress: node.progress,
1022
+ progressRole: node.progressRole,
1023
+ progressGlowAt: node.progressGlowAt,
1024
+ statusItems: node.statusItems,
1025
+ quotaWindows: node.quotaWindows,
1026
+ contextUsed: node.contextUsed,
1027
+ contextLimit: node.contextLimit,
1028
+ modHeld: node.modHeld,
1029
+ join: node.joinBottom === true,
1030
+ plain: node.plainBottom === true,
1031
+ contourRole: node.contourRole,
1032
+ contourProminence: contourP,
1033
+ });
1034
+ ops.push(...segsToPaintOps(bottomSegs, rect.x, botY, w));
1035
+ // Painted rail, not the unclipped label: a narrow frame may have dropped
1036
+ // the quota and kept occupancy, and the hit must follow what is on screen.
1037
+ const rightW = Math.max(0, segsWidth(bottomSegs.slice(1, -1)) - (w - 2));
1038
+ progressHit = {
1039
+ x: rect.x + 1,
1040
+ y: botY,
1041
+ w: Math.max(0, w - 2 - rightW),
1042
+ h: 1,
1043
+ };
1044
+ }
1045
+ // Selection/contain hit = text column only. Side │ and mark are chrome —
1046
+ // not part of the selectable draft (copy joins body lines with \n).
1047
+ const textInset = chromeFrameTextInset();
1048
+ const textW = chromeFrameContentWidth(w);
1049
+ const bodyHit = {
1050
+ x: rect.x + textInset,
1051
+ y: bodyY0,
1052
+ w: textW,
1053
+ h: Math.max(1, bodyH || 1),
1054
+ };
1055
+ // Body only. Hint-rule keys stay primary — Enter/Esc still arrive.
1056
+ // Recap (`readOnly`) keeps ordinary body voice; waiting still whispers.
1057
+ if (node.interactive === false && node.readOnly !== true) {
1058
+ const whisper = FgP.whisper;
1059
+ const bodyY1 = bodyY0 + bodyH;
1060
+ for (const op of ops) {
1061
+ if (op.kind !== "text")
1062
+ continue;
1063
+ if (op.rect.y < bodyY0 || op.rect.y >= bodyY1)
1064
+ continue;
1065
+ op.style = { ...op.style, prominence: whisper };
1066
+ }
1067
+ }
1068
+ return {
1069
+ ops,
1070
+ bodyHit,
1071
+ progressHit,
1072
+ geom: {
1073
+ ...geom,
1074
+ outerW: w,
1075
+ bodyH: bodyH || 1,
1076
+ totalH: chromeTop + (bodyH || 1) + (botY < rect.y + maxRows ? 1 : 0),
1077
+ },
1078
+ };
1079
+ }
1080
+ //# sourceMappingURL=chrome_frame.js.map