@agent-native/core 0.84.35 → 0.84.37

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 (205) hide show
  1. package/README.md +15 -51
  2. package/corpus/core/CHANGELOG.md +18 -0
  3. package/corpus/core/docs/content/actions.mdx +17 -24
  4. package/corpus/core/docs/content/agent-surfaces.mdx +59 -56
  5. package/corpus/core/docs/content/cloneable-saas.mdx +3 -3
  6. package/corpus/core/docs/content/faq.mdx +4 -4
  7. package/corpus/core/docs/content/getting-started.mdx +246 -204
  8. package/corpus/core/docs/content/key-concepts.mdx +9 -9
  9. package/corpus/core/docs/content/locales/ar-SA/cloneable-saas.mdx +3 -3
  10. package/corpus/core/docs/content/locales/ar-SA/faq.mdx +4 -4
  11. package/corpus/core/docs/content/locales/ar-SA/getting-started.mdx +148 -214
  12. package/corpus/core/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -9
  13. package/corpus/core/docs/content/locales/ar-SA/template-chat.mdx +2 -2
  14. package/corpus/core/docs/content/locales/ar-SA/using-your-agent.mdx +2 -2
  15. package/corpus/core/docs/content/locales/de-DE/cloneable-saas.mdx +3 -3
  16. package/corpus/core/docs/content/locales/de-DE/faq.mdx +4 -4
  17. package/corpus/core/docs/content/locales/de-DE/getting-started.mdx +145 -211
  18. package/corpus/core/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -9
  19. package/corpus/core/docs/content/locales/de-DE/template-chat.mdx +2 -2
  20. package/corpus/core/docs/content/locales/de-DE/using-your-agent.mdx +2 -2
  21. package/corpus/core/docs/content/locales/es-ES/cloneable-saas.mdx +3 -3
  22. package/corpus/core/docs/content/locales/es-ES/faq.mdx +4 -4
  23. package/corpus/core/docs/content/locales/es-ES/getting-started.mdx +148 -214
  24. package/corpus/core/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -9
  25. package/corpus/core/docs/content/locales/es-ES/template-chat.mdx +2 -2
  26. package/corpus/core/docs/content/locales/es-ES/using-your-agent.mdx +2 -2
  27. package/corpus/core/docs/content/locales/fr-FR/cloneable-saas.mdx +2 -2
  28. package/corpus/core/docs/content/locales/fr-FR/faq.mdx +4 -4
  29. package/corpus/core/docs/content/locales/fr-FR/getting-started.mdx +146 -212
  30. package/corpus/core/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -9
  31. package/corpus/core/docs/content/locales/fr-FR/template-chat.mdx +2 -2
  32. package/corpus/core/docs/content/locales/fr-FR/using-your-agent.mdx +2 -2
  33. package/corpus/core/docs/content/locales/hi-IN/cloneable-saas.mdx +3 -3
  34. package/corpus/core/docs/content/locales/hi-IN/faq.mdx +4 -4
  35. package/corpus/core/docs/content/locales/hi-IN/getting-started.mdx +149 -215
  36. package/corpus/core/docs/content/locales/hi-IN/pure-agent-apps.mdx +8 -13
  37. package/corpus/core/docs/content/locales/hi-IN/template-chat.mdx +2 -2
  38. package/corpus/core/docs/content/locales/hi-IN/using-your-agent.mdx +2 -2
  39. package/corpus/core/docs/content/locales/ja-JP/cloneable-saas.mdx +2 -2
  40. package/corpus/core/docs/content/locales/ja-JP/faq.mdx +4 -4
  41. package/corpus/core/docs/content/locales/ja-JP/getting-started.mdx +144 -210
  42. package/corpus/core/docs/content/locales/ja-JP/pure-agent-apps.mdx +8 -13
  43. package/corpus/core/docs/content/locales/ja-JP/template-chat.mdx +2 -2
  44. package/corpus/core/docs/content/locales/ja-JP/using-your-agent.mdx +2 -2
  45. package/corpus/core/docs/content/locales/ko-KR/cloneable-saas.mdx +3 -3
  46. package/corpus/core/docs/content/locales/ko-KR/faq.mdx +4 -4
  47. package/corpus/core/docs/content/locales/ko-KR/getting-started.mdx +146 -212
  48. package/corpus/core/docs/content/locales/ko-KR/pure-agent-apps.mdx +8 -13
  49. package/corpus/core/docs/content/locales/ko-KR/template-chat.mdx +2 -2
  50. package/corpus/core/docs/content/locales/ko-KR/using-your-agent.mdx +2 -2
  51. package/corpus/core/docs/content/locales/pt-BR/cloneable-saas.mdx +3 -3
  52. package/corpus/core/docs/content/locales/pt-BR/faq.mdx +4 -4
  53. package/corpus/core/docs/content/locales/pt-BR/getting-started.mdx +145 -211
  54. package/corpus/core/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -9
  55. package/corpus/core/docs/content/locales/pt-BR/template-chat.mdx +2 -2
  56. package/corpus/core/docs/content/locales/pt-BR/using-your-agent.mdx +2 -2
  57. package/corpus/core/docs/content/locales/zh-CN/cloneable-saas.mdx +3 -3
  58. package/corpus/core/docs/content/locales/zh-CN/faq.mdx +4 -4
  59. package/corpus/core/docs/content/locales/zh-CN/getting-started.mdx +158 -209
  60. package/corpus/core/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -9
  61. package/corpus/core/docs/content/locales/zh-CN/template-chat.mdx +2 -2
  62. package/corpus/core/docs/content/locales/zh-CN/using-your-agent.mdx +2 -2
  63. package/corpus/core/docs/content/locales/zh-TW/cloneable-saas.mdx +3 -3
  64. package/corpus/core/docs/content/locales/zh-TW/faq.mdx +4 -4
  65. package/corpus/core/docs/content/locales/zh-TW/getting-started.mdx +158 -212
  66. package/corpus/core/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -9
  67. package/corpus/core/docs/content/locales/zh-TW/template-chat.mdx +2 -2
  68. package/corpus/core/docs/content/locales/zh-TW/using-your-agent.mdx +2 -2
  69. package/corpus/core/docs/content/native-chat-ui.mdx +17 -32
  70. package/corpus/core/docs/content/pure-agent-apps.mdx +46 -26
  71. package/corpus/core/docs/content/template-chat.mdx +8 -8
  72. package/corpus/core/docs/content/using-your-agent.mdx +2 -2
  73. package/corpus/core/docs/content/what-is-agent-native.mdx +6 -6
  74. package/corpus/core/package.json +1 -1
  75. package/corpus/core/src/cli/skills.ts +7 -9
  76. package/corpus/core/src/client/AssistantChat.tsx +27 -13
  77. package/corpus/core/src/client/MultiTabAssistantChat.tsx +2 -0
  78. package/corpus/core/src/client/RunStuckBanner.tsx +195 -21
  79. package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +57 -9
  80. package/corpus/core/src/client/blocks/library/wireframe.tsx +3 -18
  81. package/corpus/core/src/client/chat/widgets/builtin-tool-renderers.tsx +28 -32
  82. package/corpus/core/src/client/use-run-stuck-detection.ts +14 -1
  83. package/corpus/core/src/db/schema.ts +5 -0
  84. package/corpus/core/src/server/agent-chat-plugin.ts +5 -2
  85. package/corpus/core/src/styles/blocks.css +27 -6
  86. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -4
  87. package/corpus/templates/content/actions/list-trashed-content-databases.ts +1 -1
  88. package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -9
  89. package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -9
  90. package/dist/cli/skills.d.ts +1 -1
  91. package/dist/cli/skills.d.ts.map +1 -1
  92. package/dist/cli/skills.js +7 -9
  93. package/dist/cli/skills.js.map +1 -1
  94. package/dist/client/AssistantChat.d.ts +6 -0
  95. package/dist/client/AssistantChat.d.ts.map +1 -1
  96. package/dist/client/AssistantChat.js +19 -13
  97. package/dist/client/AssistantChat.js.map +1 -1
  98. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  99. package/dist/client/MultiTabAssistantChat.js +1 -1
  100. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  101. package/dist/client/RunStuckBanner.d.ts +13 -1
  102. package/dist/client/RunStuckBanner.d.ts.map +1 -1
  103. package/dist/client/RunStuckBanner.js +138 -16
  104. package/dist/client/RunStuckBanner.js.map +1 -1
  105. package/dist/client/blocks/library/wireframe-kit.d.ts +6 -6
  106. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  107. package/dist/client/blocks/library/wireframe-kit.js +52 -5
  108. package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
  109. package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
  110. package/dist/client/blocks/library/wireframe.js +1 -11
  111. package/dist/client/blocks/library/wireframe.js.map +1 -1
  112. package/dist/client/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
  113. package/dist/client/chat/widgets/builtin-tool-renderers.js +27 -31
  114. package/dist/client/chat/widgets/builtin-tool-renderers.js.map +1 -1
  115. package/dist/client/use-run-stuck-detection.d.ts +4 -0
  116. package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
  117. package/dist/client/use-run-stuck-detection.js +7 -1
  118. package/dist/client/use-run-stuck-detection.js.map +1 -1
  119. package/dist/collab/awareness.d.ts +2 -2
  120. package/dist/collab/awareness.d.ts.map +1 -1
  121. package/dist/collab/routes.d.ts +1 -1
  122. package/dist/db/schema.d.ts +2 -1
  123. package/dist/db/schema.d.ts.map +1 -1
  124. package/dist/db/schema.js +3 -2
  125. package/dist/db/schema.js.map +1 -1
  126. package/dist/notifications/routes.d.ts +3 -3
  127. package/dist/progress/routes.d.ts +1 -1
  128. package/dist/resources/handlers.d.ts +3 -3
  129. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  130. package/dist/server/agent-chat-plugin.js +3 -2
  131. package/dist/server/agent-chat-plugin.js.map +1 -1
  132. package/dist/server/transcribe-voice.d.ts +1 -1
  133. package/dist/styles/blocks.css +27 -6
  134. package/docs/content/actions.mdx +17 -24
  135. package/docs/content/agent-surfaces.mdx +59 -56
  136. package/docs/content/cloneable-saas.mdx +3 -3
  137. package/docs/content/faq.mdx +4 -4
  138. package/docs/content/getting-started.mdx +246 -204
  139. package/docs/content/key-concepts.mdx +9 -9
  140. package/docs/content/locales/ar-SA/cloneable-saas.mdx +3 -3
  141. package/docs/content/locales/ar-SA/faq.mdx +4 -4
  142. package/docs/content/locales/ar-SA/getting-started.mdx +148 -214
  143. package/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -9
  144. package/docs/content/locales/ar-SA/template-chat.mdx +2 -2
  145. package/docs/content/locales/ar-SA/using-your-agent.mdx +2 -2
  146. package/docs/content/locales/de-DE/cloneable-saas.mdx +3 -3
  147. package/docs/content/locales/de-DE/faq.mdx +4 -4
  148. package/docs/content/locales/de-DE/getting-started.mdx +145 -211
  149. package/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -9
  150. package/docs/content/locales/de-DE/template-chat.mdx +2 -2
  151. package/docs/content/locales/de-DE/using-your-agent.mdx +2 -2
  152. package/docs/content/locales/es-ES/cloneable-saas.mdx +3 -3
  153. package/docs/content/locales/es-ES/faq.mdx +4 -4
  154. package/docs/content/locales/es-ES/getting-started.mdx +148 -214
  155. package/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -9
  156. package/docs/content/locales/es-ES/template-chat.mdx +2 -2
  157. package/docs/content/locales/es-ES/using-your-agent.mdx +2 -2
  158. package/docs/content/locales/fr-FR/cloneable-saas.mdx +2 -2
  159. package/docs/content/locales/fr-FR/faq.mdx +4 -4
  160. package/docs/content/locales/fr-FR/getting-started.mdx +146 -212
  161. package/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -9
  162. package/docs/content/locales/fr-FR/template-chat.mdx +2 -2
  163. package/docs/content/locales/fr-FR/using-your-agent.mdx +2 -2
  164. package/docs/content/locales/hi-IN/cloneable-saas.mdx +3 -3
  165. package/docs/content/locales/hi-IN/faq.mdx +4 -4
  166. package/docs/content/locales/hi-IN/getting-started.mdx +149 -215
  167. package/docs/content/locales/hi-IN/pure-agent-apps.mdx +8 -13
  168. package/docs/content/locales/hi-IN/template-chat.mdx +2 -2
  169. package/docs/content/locales/hi-IN/using-your-agent.mdx +2 -2
  170. package/docs/content/locales/ja-JP/cloneable-saas.mdx +2 -2
  171. package/docs/content/locales/ja-JP/faq.mdx +4 -4
  172. package/docs/content/locales/ja-JP/getting-started.mdx +144 -210
  173. package/docs/content/locales/ja-JP/pure-agent-apps.mdx +8 -13
  174. package/docs/content/locales/ja-JP/template-chat.mdx +2 -2
  175. package/docs/content/locales/ja-JP/using-your-agent.mdx +2 -2
  176. package/docs/content/locales/ko-KR/cloneable-saas.mdx +3 -3
  177. package/docs/content/locales/ko-KR/faq.mdx +4 -4
  178. package/docs/content/locales/ko-KR/getting-started.mdx +146 -212
  179. package/docs/content/locales/ko-KR/pure-agent-apps.mdx +8 -13
  180. package/docs/content/locales/ko-KR/template-chat.mdx +2 -2
  181. package/docs/content/locales/ko-KR/using-your-agent.mdx +2 -2
  182. package/docs/content/locales/pt-BR/cloneable-saas.mdx +3 -3
  183. package/docs/content/locales/pt-BR/faq.mdx +4 -4
  184. package/docs/content/locales/pt-BR/getting-started.mdx +145 -211
  185. package/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -9
  186. package/docs/content/locales/pt-BR/template-chat.mdx +2 -2
  187. package/docs/content/locales/pt-BR/using-your-agent.mdx +2 -2
  188. package/docs/content/locales/zh-CN/cloneable-saas.mdx +3 -3
  189. package/docs/content/locales/zh-CN/faq.mdx +4 -4
  190. package/docs/content/locales/zh-CN/getting-started.mdx +158 -209
  191. package/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -9
  192. package/docs/content/locales/zh-CN/template-chat.mdx +2 -2
  193. package/docs/content/locales/zh-CN/using-your-agent.mdx +2 -2
  194. package/docs/content/locales/zh-TW/cloneable-saas.mdx +3 -3
  195. package/docs/content/locales/zh-TW/faq.mdx +4 -4
  196. package/docs/content/locales/zh-TW/getting-started.mdx +158 -212
  197. package/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -9
  198. package/docs/content/locales/zh-TW/template-chat.mdx +2 -2
  199. package/docs/content/locales/zh-TW/using-your-agent.mdx +2 -2
  200. package/docs/content/native-chat-ui.mdx +17 -32
  201. package/docs/content/pure-agent-apps.mdx +46 -26
  202. package/docs/content/template-chat.mdx +8 -8
  203. package/docs/content/using-your-agent.mdx +2 -2
  204. package/docs/content/what-is-agent-native.mdx +6 -6
  205. package/package.json +1 -1
@@ -26,10 +26,10 @@ import type {
26
26
  * DECOUPLING: the only behavioral change from the plan copy is theme detection —
27
27
  * core blocks read `document.documentElement.classList.contains("dark")` (the
28
28
  * MermaidBlock precedent) instead of importing `next-themes`. Everything else
29
- * (the `.plan-wf` / `[data-rough]` class contract the rough overlay measures,
30
- * the `--wf-*` / `--ink` / `--paper` token names every primitive reads) is
31
- * preserved exactly, so the kit looks identical in plan and renders correctly in
32
- * any app once the matching tokens exist in `core/styles/blocks.css`.
29
+ * (the `.plan-wf` / `.wf-*` / `[data-rough]` class contract the rough overlay
30
+ * measures, the `--wf-*` / `--ink` / `--paper` token names every primitive
31
+ * reads) is preserved exactly, so the kit looks identical in plan and renders
32
+ * correctly in any app once the matching tokens exist in `core/styles/blocks.css`.
33
33
  */
34
34
 
35
35
  /* ========================================================================== */
@@ -211,7 +211,7 @@ export function Screen({
211
211
  // clipping. The frame shell (`ArtboardFrame`) owns the height policy; a
212
212
  // caller can still override via `style.height` for a fixed canvas.
213
213
  minHeight: "100%",
214
- background: V.paper,
214
+ background: "transparent",
215
215
  color: V.ink,
216
216
  fontFamily: V.hand,
217
217
  fontSize: V.fs,
@@ -1425,9 +1425,9 @@ const gen = rough.generator();
1425
1425
 
1426
1426
  type RoughPath = { d: string; stroke: string; strokeWidth: number };
1427
1427
 
1428
- /** The default selector used for HTML mockups: controls plus explicit opt-ins. */
1428
+ /** The default selector used for HTML mockups: standard wireframe primitives plus explicit opt-ins. */
1429
1429
  export const HTML_ROUGH_SELECTOR =
1430
- "[data-rough],button,input,textarea,select,hr";
1430
+ "[data-rough],button,input,textarea,select,hr,.wf-btn,.wf-card,.wf-box,.wf-pill,.wf-chip,.wf-icon-fallback,[style*='border:'],[style*='border-top:'],[style*='border-right:'],[style*='border-bottom:'],[style*='border-left:']";
1431
1431
 
1432
1432
  /** Stable per-element seed so a frame doesn't re-wobble on every measure. */
1433
1433
  function seedFrom(...parts: Array<string | number>): number {
@@ -1528,6 +1528,50 @@ function elementStroke(node: Element, fallback: string): string {
1528
1528
  return fallback;
1529
1529
  }
1530
1530
 
1531
+ function visibleBorderSides(
1532
+ node: Element,
1533
+ ): Array<"top" | "right" | "bottom" | "left"> {
1534
+ const cs = getComputedStyle(node);
1535
+ const sides: Array<"top" | "right" | "bottom" | "left"> = [];
1536
+ for (const [side, widthProp, colorProp] of [
1537
+ ["top", "borderTopWidth", "borderTopColor"],
1538
+ ["right", "borderRightWidth", "borderRightColor"],
1539
+ ["bottom", "borderBottomWidth", "borderBottomColor"],
1540
+ ["left", "borderLeftWidth", "borderLeftColor"],
1541
+ ] as const) {
1542
+ const width = parseFloat(cs[widthProp]);
1543
+ const color = cs[colorProp];
1544
+ if (
1545
+ width > 0 &&
1546
+ color &&
1547
+ color !== "rgba(0, 0, 0, 0)" &&
1548
+ color !== "transparent"
1549
+ ) {
1550
+ sides.push(side);
1551
+ }
1552
+ }
1553
+ return sides;
1554
+ }
1555
+
1556
+ function inferRoughKind(node: HTMLElement): string {
1557
+ const explicit = node.getAttribute("data-rough");
1558
+ if (explicit) return explicit;
1559
+ if (node.tagName === "HR") return "line:middle";
1560
+ const sides = visibleBorderSides(node);
1561
+ if (sides.length !== 1) return "rect";
1562
+ switch (sides[0]) {
1563
+ case "top":
1564
+ return "line:top";
1565
+ case "right":
1566
+ return "line:right";
1567
+ case "bottom":
1568
+ return "line:bottom";
1569
+ case "left":
1570
+ return "line:left";
1571
+ }
1572
+ return "rect";
1573
+ }
1574
+
1531
1575
  function build(
1532
1576
  scope: HTMLElement,
1533
1577
  opts: {
@@ -1602,7 +1646,7 @@ function build(
1602
1646
  const w = r.width / zoom;
1603
1647
  const h = r.height / zoom;
1604
1648
  if (w < 2 || h < 2) return;
1605
- const kind = node.getAttribute("data-rough") || "rect";
1649
+ const kind = inferRoughKind(node);
1606
1650
  const rawStroke = elementStroke(node, sketch);
1607
1651
  const stroke =
1608
1652
  sameColor(rawStroke, ink) || (line !== "" && sameColor(rawStroke, line))
@@ -1621,11 +1665,15 @@ function build(
1621
1665
  let drawable: unknown;
1622
1666
  if (kind === "ellipse") {
1623
1667
  drawable = gen.ellipse(x + w / 2, y + h / 2, w, h, o);
1668
+ } else if (kind === "line:left") {
1669
+ drawable = gen.line(x, y, x, y + h, o);
1624
1670
  } else if (kind === "line:right") {
1625
1671
  drawable = gen.line(x + w, y, x + w, y + h, o);
1626
1672
  } else if (kind === "line:bottom") {
1627
1673
  drawable = gen.line(x, y + h, x + w, y + h, o);
1628
- } else if (kind === "line:top" || node.tagName === "HR") {
1674
+ } else if (kind === "line:top") {
1675
+ drawable = gen.line(x, y, x + w, y, o);
1676
+ } else if (kind === "line:middle") {
1629
1677
  drawable = gen.line(x, y + h / 2, x + w, y + h / 2, o);
1630
1678
  } else {
1631
1679
  const cr = parseFloat(getComputedStyle(node).borderTopLeftRadius) || 0;
@@ -56,8 +56,8 @@ import {
56
56
  * - The plan-only prototype runtime, design-element selection, and legacy region
57
57
  * fallback are intentionally NOT ported; those are plan-canvas features, not
58
58
  * part of the document-block render. The kit element vocabulary, the `--wf-*`
59
- * token contract, and the `.plan-wf` / `[data-rough]` classes the overlay
60
- * measures are preserved exactly.
59
+ * token contract, and the `.plan-wf` / `.wf-*` / `[data-rough]` classes the
60
+ * overlay measures are preserved exactly.
61
61
  *
62
62
  * The section carries the app-neutral `an-block` class plus the legacy
63
63
  * `plan-block` class so plan renders byte-identically while any other app gets
@@ -164,12 +164,6 @@ function ArtboardFrame({
164
164
  const designMode = renderMode === "design";
165
165
  const sketchy = !designMode && style === "sketchy" && !skeleton;
166
166
  const roughEnabled = sketchy && roughOverlay;
167
- const paper = designMode
168
- ? "hsl(var(--background))"
169
- : "var(--plan-document, hsl(var(--background)))";
170
- const frameBorder = skeleton
171
- ? "var(--plan-placeholder-line, var(--plan-line, hsl(var(--border))))"
172
- : "var(--plan-line, hsl(var(--border)))";
173
167
 
174
168
  useEffect(() => {
175
169
  const element = fitRef.current;
@@ -243,7 +237,6 @@ function ArtboardFrame({
243
237
  // a fixed `canvasSize` locks the height for canvas artboards.
244
238
  ...(fixedHeight != null ? { height: fixedHeight } : { minHeight }),
245
239
  borderRadius: preset.radius,
246
- background: paper,
247
240
  ...(fitScale !== 1
248
241
  ? {
249
242
  transform: `scale(${fitScale})`,
@@ -266,18 +259,10 @@ function ArtboardFrame({
266
259
  >
267
260
  {render({ theme, style })}
268
261
  </div>
269
- {!roughEnabled && (
270
- <div
271
- className="pointer-events-none absolute inset-0"
272
- style={{
273
- borderRadius: preset.radius,
274
- border: `1.5px solid ${frameBorder}`,
275
- }}
276
- />
277
- )}
278
262
  <RoughOverlay
279
263
  scopeRef={ref}
280
264
  enabled={roughEnabled}
265
+ drawFrame={false}
281
266
  frameRadius={preset.radius}
282
267
  selector={selector}
283
268
  />
@@ -34,10 +34,37 @@ function isRecord(value: unknown): value is Record<string, unknown> {
34
34
  function normalizeActionDataWidgetResult(
35
35
  context: ToolRendererContext,
36
36
  ): DataWidgetResult | null {
37
+ const renderer = context.chatUI?.renderer;
38
+ if (isRecord(context.resultJson)) {
39
+ if (renderer === ACTION_CHAT_UI_DATA_TABLE_RENDERER) {
40
+ return normalizeDataWidgetResult({
41
+ ...context.resultJson,
42
+ widget: DATA_TABLE_WIDGET,
43
+ table: isRecord(context.resultJson.table)
44
+ ? context.resultJson.table
45
+ : context.resultJson,
46
+ });
47
+ }
48
+ if (renderer === ACTION_CHAT_UI_DATA_CHART_RENDERER) {
49
+ return normalizeDataWidgetResult({
50
+ ...context.resultJson,
51
+ widget: DATA_CHART_WIDGET,
52
+ chartSeries: isRecord(context.resultJson.chartSeries)
53
+ ? context.resultJson.chartSeries
54
+ : context.resultJson,
55
+ });
56
+ }
57
+ if (renderer === ACTION_CHAT_UI_DATA_INSIGHTS_RENDERER) {
58
+ return normalizeDataWidgetResult({
59
+ ...context.resultJson,
60
+ widget: DATA_INSIGHTS_WIDGET,
61
+ });
62
+ }
63
+ }
64
+
37
65
  const result = normalizeDataWidgetResult(context.resultJson);
38
66
  if (result) return result;
39
67
 
40
- const renderer = context.chatUI?.renderer;
41
68
  if (
42
69
  renderer === ACTION_CHAT_UI_DATA_WIDGET_RENDERER ||
43
70
  context.toolName === "render-data-widget"
@@ -46,37 +73,6 @@ function normalizeActionDataWidgetResult(
46
73
  if (argsResult) return argsResult;
47
74
  }
48
75
 
49
- if (!isRecord(context.resultJson)) return null;
50
-
51
- if (renderer === ACTION_CHAT_UI_DATA_TABLE_RENDERER) {
52
- return normalizeDataWidgetResult({
53
- widget: DATA_TABLE_WIDGET,
54
- table: isRecord(context.resultJson.table)
55
- ? context.resultJson.table
56
- : context.resultJson,
57
- display: isRecord(context.resultJson.display)
58
- ? context.resultJson.display
59
- : undefined,
60
- });
61
- }
62
- if (renderer === ACTION_CHAT_UI_DATA_CHART_RENDERER) {
63
- return normalizeDataWidgetResult({
64
- widget: DATA_CHART_WIDGET,
65
- chartSeries: isRecord(context.resultJson.chartSeries)
66
- ? context.resultJson.chartSeries
67
- : context.resultJson,
68
- display: isRecord(context.resultJson.display)
69
- ? context.resultJson.display
70
- : undefined,
71
- });
72
- }
73
- if (renderer === ACTION_CHAT_UI_DATA_INSIGHTS_RENDERER) {
74
- return normalizeDataWidgetResult({
75
- ...context.resultJson,
76
- widget: DATA_INSIGHTS_WIDGET,
77
- });
78
- }
79
-
80
76
  return null;
81
77
  }
82
78
 
@@ -24,6 +24,10 @@ export interface RunStuckState {
24
24
  stuckSinceMs: number | null;
25
25
  /** Server timestamp (ms) of the last process-alive heartbeat. */
26
26
  heartbeatAt: number | null;
27
+ /** Milliseconds since `heartbeatAt`, computed against the server clock. */
28
+ heartbeatSinceMs: number | null;
29
+ /** How the run was dispatched, e.g. foreground or background-processing. */
30
+ dispatchMode: string | null;
27
31
  }
28
32
 
29
33
  export interface UseRunStuckDetectionOptions {
@@ -51,6 +55,7 @@ interface ActiveRunResponse {
51
55
  status?: string;
52
56
  heartbeatAt: number | null;
53
57
  lastProgressAt?: number | null;
58
+ dispatchMode?: string | null;
54
59
  /** Server clock at response time, used to compute elapsed server-relative. */
55
60
  serverNow?: number;
56
61
  }
@@ -62,6 +67,8 @@ const EMPTY_STATE: RunStuckState = {
62
67
  lastProgressAt: null,
63
68
  stuckSinceMs: null,
64
69
  heartbeatAt: null,
70
+ heartbeatSinceMs: null,
71
+ dispatchMode: null,
65
72
  };
66
73
 
67
74
  export function useRunStuckDetection({
@@ -102,6 +109,9 @@ export function useRunStuckDetection({
102
109
  const nowMs = data.serverNow ?? Date.now();
103
110
  const stuckSinceMs =
104
111
  lastProgressAt != null ? nowMs - lastProgressAt : null;
112
+ const heartbeatAt = data.heartbeatAt ?? null;
113
+ const heartbeatSinceMs =
114
+ heartbeatAt != null ? nowMs - heartbeatAt : null;
105
115
  const isStuck = Boolean(
106
116
  data.active &&
107
117
  data.status === "running" &&
@@ -114,7 +124,10 @@ export function useRunStuckDetection({
114
124
  status: data.status ?? null,
115
125
  lastProgressAt,
116
126
  stuckSinceMs,
117
- heartbeatAt: data.heartbeatAt ?? null,
127
+ heartbeatAt,
128
+ heartbeatSinceMs,
129
+ dispatchMode:
130
+ typeof data.dispatchMode === "string" ? data.dispatchMode : null,
118
131
  });
119
132
  // Back off polling when nothing is in flight — there's no point
120
133
  // hammering the endpoint while the chat is idle. We still poll
@@ -19,6 +19,7 @@
19
19
  import { sql } from "drizzle-orm";
20
20
  import {
21
21
  pgTable,
22
+ alias as pgAlias,
22
23
  index as pgIndex,
23
24
  text as pgText,
24
25
  integer as pgInteger,
@@ -28,6 +29,7 @@ import {
28
29
  } from "drizzle-orm/pg-core";
29
30
  import {
30
31
  sqliteTable,
32
+ alias as sqliteAlias,
31
33
  index as sqliteIndex,
32
34
  text as sqliteText,
33
35
  integer as sqliteInteger,
@@ -50,6 +52,9 @@ function pg(): boolean {
50
52
  export const table: typeof sqliteTable = ((...args: any[]) =>
51
53
  pg() ? (pgTable as any)(...args) : (sqliteTable as any)(...args)) as any;
52
54
 
55
+ export const alias: typeof sqliteAlias = ((...args: any[]) =>
56
+ pg() ? (pgAlias as any)(...args) : (sqliteAlias as any)(...args)) as any;
57
+
53
58
  export const index: typeof sqliteIndex = ((...args: any[]) =>
54
59
  pg() ? (pgIndex as any)(...args) : (sqliteIndex as any)(...args)) as any;
55
60
 
@@ -7278,8 +7278,11 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
7278
7278
  let reason = "user";
7279
7279
  try {
7280
7280
  const body = await readBody(event);
7281
- if (body?.reason === "no_progress") {
7282
- reason = "no_progress";
7281
+ if (
7282
+ typeof body?.reason === "string" &&
7283
+ /^[a-z0-9_-]{1,64}$/i.test(body.reason)
7284
+ ) {
7285
+ reason = body.reason;
7283
7286
  }
7284
7287
  } catch {
7285
7288
  // Empty/invalid body — keep the default user abort reason.
@@ -995,7 +995,7 @@
995
995
  min-height: 100%;
996
996
  overflow: hidden;
997
997
  box-sizing: border-box;
998
- background: var(--wf-paper);
998
+ background: transparent;
999
999
  color: var(--wf-ink);
1000
1000
  font-family: var(--wf-font);
1001
1001
  font-size: 14px;
@@ -1177,6 +1177,16 @@
1177
1177
  border-radius: var(--wf-radius);
1178
1178
  padding: 12px;
1179
1179
  }
1180
+ .plan-html-frame:not([data-render-mode="design"]) .wf-row {
1181
+ display: flex;
1182
+ align-items: center;
1183
+ justify-content: space-between;
1184
+ gap: 10px;
1185
+ }
1186
+ .plan-html-frame:not([data-render-mode="design"]) .wf-row > :last-child {
1187
+ margin-inline-start: auto;
1188
+ text-align: end;
1189
+ }
1180
1190
  .plan-html-frame[data-style="sketchy"]:not([data-render-mode="design"])
1181
1191
  :is(.wf-card, .wf-box) {
1182
1192
  border-color: color-mix(in srgb, var(--wf-line) 72%, transparent);
@@ -1197,9 +1207,9 @@
1197
1207
  background: var(--wf-accent-soft);
1198
1208
  }
1199
1209
 
1200
- /* Once rough has drawn, hide crisp borders only on elements rough.js actually
1201
- redraws. Broad helper containers keep theme-safe filled backgrounds and soft
1202
- borders so nested cards do not become a pile of overlapping sketch strokes. */
1210
+ /* Once rough has drawn, hide crisp borders on the standard wireframe primitives
1211
+ that rough.js redraws. Fills and text stay in CSS; only outlines switch to
1212
+ the hand-drawn overlay. */
1203
1213
  .plan-html-frame[data-rough-ready]
1204
1214
  :is(
1205
1215
  button,
@@ -1207,8 +1217,19 @@
1207
1217
  textarea,
1208
1218
  select,
1209
1219
  hr,
1210
- [data-rough]:not([data-rough="none"])
1211
- ) {
1220
+ .wf-btn,
1221
+ .wf-card,
1222
+ .wf-box,
1223
+ .wf-pill,
1224
+ .wf-chip,
1225
+ .wf-icon-fallback,
1226
+ [style*="border:"],
1227
+ [style*="border-top:"],
1228
+ [style*="border-right:"],
1229
+ [style*="border-bottom:"],
1230
+ [style*="border-left:"],
1231
+ [data-rough]
1232
+ ):not([data-rough="none"]) {
1212
1233
  border-color: transparent !important;
1213
1234
  }
1214
1235
 
@@ -1348,9 +1348,6 @@ function AnalyticsChatsSection() {
1348
1348
 
1349
1349
  return (
1350
1350
  <div className="ms-4 min-w-0 space-y-0.5">
1351
- <p className="min-w-0 truncate px-3 pb-0.5 pt-1 text-[11px] font-medium text-muted-foreground/70">
1352
- {t("chat.recentChats")}
1353
- </p>
1354
1351
  {visibleThreads.map((thread) => {
1355
1352
  const title = threadTitle(thread, t("chat.untitledChat"));
1356
1353
  const isActive =
@@ -1395,7 +1392,7 @@ function AnalyticsChatsSection() {
1395
1392
  <button
1396
1393
  type="button"
1397
1394
  onClick={() => openThread(thread.id)}
1398
- className="min-w-0 flex-1 px-2 py-1.5 pe-12 text-start text-xs outline-none transition-[padding] focus-visible:ring-2 focus-visible:ring-ring md:pe-2 md:group-hover/item:pe-12 md:group-focus-within/item:pe-12"
1395
+ className="min-w-0 flex-1 px-2 py-1.5 pe-12 text-start text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring"
1399
1396
  >
1400
1397
  <span className="block truncate">{title}</span>
1401
1398
  </button>
@@ -1,7 +1,7 @@
1
1
  import { defineAction } from "@agent-native/core";
2
+ import { alias } from "@agent-native/core/db/schema";
2
3
  import { accessFilter } from "@agent-native/core/sharing";
3
4
  import { and, desc, eq, isNotNull, isNull, ne, or } from "drizzle-orm";
4
- import { alias } from "drizzle-orm/sqlite-core";
5
5
  import { z } from "zod";
6
6
 
7
7
  import { getDb, schema } from "../server/db/index.js";
@@ -75,15 +75,13 @@ background, text, border, ring, fill, stroke, gradient, placeholder, decoration,
75
75
  or shadow color, rewrite it to renderer tokens or remove it. Layout-only classes
76
76
  are still discouraged; inline flex/grid styles are safer and easier to review.
77
77
 
78
- **Keep Rough.js sparse.** `.wf-card` and `.wf-box` already render with
79
- theme-safe filled backgrounds (`--wf-card`) and soft tokenized borders that work
80
- in both light and dark mode. Do not add `data-rough` to broad root wrappers,
81
- dialog shells, page panels, grid cells, or nested containers unless that single
82
- container is the visual point. The renderer sketches the outer frame and
83
- standard controls by default; use `data-rough` only for a deliberate one-off
84
- shape. If a mockup starts looking like stacked/overlapping sketch lines, remove
85
- rough targets from parent containers and let backgrounds plus spacing separate
86
- the surfaces.
78
+ **Keep Rough.js sparse.** The renderer sketches the outer frame, standard
79
+ `.wf-*` primitives, controls, and inline border dividers by default. Do not add
80
+ `data-rough` to broad root wrappers, dialog shells, page panels, grid cells, or
81
+ nested containers unless that single container is the visual point. Use
82
+ `data-rough` only for a deliberate one-off shape. If a mockup starts looking
83
+ like stacked/overlapping sketch lines, remove rough targets from parent
84
+ containers and let backgrounds plus spacing separate the surfaces.
87
85
 
88
86
  **Use literal CSS lengths for spacing.** The `--wf-*` tokens are for colors and
89
87
  renderer-owned visual styling, not layout spacing. Do not use guessed spacing
@@ -75,15 +75,13 @@ background, text, border, ring, fill, stroke, gradient, placeholder, decoration,
75
75
  or shadow color, rewrite it to renderer tokens or remove it. Layout-only classes
76
76
  are still discouraged; inline flex/grid styles are safer and easier to review.
77
77
 
78
- **Keep Rough.js sparse.** `.wf-card` and `.wf-box` already render with
79
- theme-safe filled backgrounds (`--wf-card`) and soft tokenized borders that work
80
- in both light and dark mode. Do not add `data-rough` to broad root wrappers,
81
- dialog shells, page panels, grid cells, or nested containers unless that single
82
- container is the visual point. The renderer sketches the outer frame and
83
- standard controls by default; use `data-rough` only for a deliberate one-off
84
- shape. If a mockup starts looking like stacked/overlapping sketch lines, remove
85
- rough targets from parent containers and let backgrounds plus spacing separate
86
- the surfaces.
78
+ **Keep Rough.js sparse.** The renderer sketches the outer frame, standard
79
+ `.wf-*` primitives, controls, and inline border dividers by default. Do not add
80
+ `data-rough` to broad root wrappers, dialog shells, page panels, grid cells, or
81
+ nested containers unless that single container is the visual point. Use
82
+ `data-rough` only for a deliberate one-off shape. If a mockup starts looking
83
+ like stacked/overlapping sketch lines, remove rough targets from parent
84
+ containers and let backgrounds plus spacing separate the surfaces.
87
85
 
88
86
  **Use literal CSS lengths for spacing.** The `--wf-*` tokens are for colors and
89
87
  renderer-owned visual styling, not layout spacing. Do not use guessed spacing
@@ -6,7 +6,7 @@
6
6
  import { type AppSkillManifest } from "./app-skill.js";
7
7
  import { type ClientId } from "./mcp-config-writers.js";
8
8
  import { type CliTelemetry } from "./telemetry.js";
9
- export declare const WIREFRAME_REFERENCE_MD = "# HTML wireframe quality \u2014 single source of truth\n\nThis file is the canonical quality bar for HTML wireframes / `<Screen>` /\n`WireframeBlock` content, shared word for word by `/visual-plan` and\n`/visual-recap`. Read it in full before authoring ANY wireframe; do not\nauthor wireframes from memory or paraphrase these rules per command.\n\n<!-- SHARED-CORE:wireframe-quality START -->\n\n**A wireframe is an HTML mockup. The renderer owns the look; you write the\ncontent.** Set `data.html` to a self-contained, semantic HTML fragment of the\nscreen and set `data.surface`. The renderer owns the surface footprint/aspect,\nthe dark/light theme, the hand-drawn font, and the rough.js sketch overlay \u2014 you\nnever write `<html>`/`<body>`/`<script>`/`<style>` tags or any\nwidth/height/coordinates. You write real HTML layout and real product\ncontent; the renderer styles and roughens it.\n\n**A wireframe block's data is an HTML screen plus a surface:**\n\n```json\n{\n \"surface\": \"browser\",\n \"html\": \"<div style=\\\"display:flex;flex-direction:column;gap:10px;padding:16px;height:100%\\\"><h1>Sign in</h1><p class=\\\"wf-muted\\\">Use your work email to continue.</p><div class=\\\"wf-card\\\" style=\\\"display:flex;flex-direction:column;gap:10px\\\"><label>Email<input value=\\\"jane@acme.co\\\" /></label><label>Password<input value=\\\"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\\\" /></label><label style=\\\"display:flex;align-items:center;gap:8px\\\"><input type=\\\"checkbox\\\" checked /> Remember me</label><button class=\\\"primary\\\">Sign in</button></div><a href=\\\"#\\\">Forgot password?</a></div>\"\n}\n```\n\n**Write PLAIN semantic HTML and let the renderer style it.** Bare elements\n(`h1`/`h2`/`h3`, `p`, `button`, `input`, `<input type=\"checkbox\">`, `a`, `hr`)\nare auto-themed \u2014 no classes needed. Helper classes carry the rest:\n\n- `.wf-card` / `.wf-box` \u2014 a bordered, padded container (a panel, a list item).\n- `.wf-pill` / `.wf-chip` \u2014 a rounded tag or filter; add `.accent`\n (`<span class=\"wf-pill accent\">`) for the accent-filled variant.\n- `.wf-muted` \u2014 secondary/muted text (or use `<small>`).\n- `button.primary` or any element with `[data-primary]` \u2014 the accent-filled\n primary button.\n\n**No decorative shadows around mockups.** Do not put `box-shadow`, `filter:\ndrop-shadow(...)`, Tailwind `shadow-*` classes, or other fake depth effects on a\nwireframe frame, root container, `.wf-card` / `.wf-box`, or canvas artboard.\nMockups should read as flat, bordered surfaces; use spacing, borders, labels,\nand annotations for separation. Only show a shadow when the real product UI\nalready has that shadow and it is essential to the change being reviewed.\n\n**Use renderer icons, not visible icon words.** For icon-only buttons or leading\nicons inside fields, chips, menu items, and toolbars, write an empty marker such\nas `<span data-icon=\"mail\" aria-label=\"Email\"></span>` or\n`<i data-icon=\"lock\"></i>`. The renderer replaces it with a Tabler-style SVG and\nthe `.wf-icon` class sizes it to the surrounding text. Supported names and\naliases: `mail`/`email`, `lock`/`password`, `search`, `plus`/`add`, `x`/`close`,\n`check`, `chevronDown`, `chevronUp`, `chevronLeft`, `chevronRight`, `dots`/`more`,\n`chevron`/`caret`/`dropdown` (down chevron), `user`, `settings`, `calendar`,\n`bell`, `send`, `edit`, `arrowLeft`, and `arrowRight`. Do not put visible words\nlike \"email\", \"lock\", \"search\", \"chevron\", or \"more\" where the product UI would\nshow an icon; use text only when it is a real label a user would read.\n\n**Use the `--wf-*` tokens for any custom color, never hex.** The renderer flips\nthese on light/dark, so reading them is what keeps a mockup correct in both\nthemes. For any inline border, background, or text color, reference a token:\n`style=\"border:1.4px solid var(--wf-line)\"`. The tokens are `--wf-ink` (text),\n`--wf-muted` (secondary text), `--wf-line` (borders/dividers), `--wf-paper`\n(page background), `--wf-card` (container surface), `--wf-accent` /\n`--wf-accent-fg` / `--wf-accent-soft` (brand action), `--wf-warn`, `--wf-ok`,\nand `--wf-radius`. Never hard-code a hex color and never set `font-family` \u2014 the\nrenderer owns the sketch/clean font.\n\n**Never use host/Tailwind theme classes in wireframe HTML.** Classes such as\n`bg-white`, `bg-zinc-50`, `bg-slate-950`, `text-zinc-950`,\n`text-slate-400`, `border-zinc-200`, `hover:bg-slate-800`, `shadow-xl`,\nor arbitrary color utilities like `bg-[#fff]` leak the host app's CSS into the\nmockup and can make dark-mode canvas frames unreadable. Use bare semantic\nelements, `.wf-*` helper classes, and `--wf-*` color tokens instead. Before\npublishing, scan every wireframe `class` and `style` attribute: if a class sets\nbackground, text, border, ring, fill, stroke, gradient, placeholder, decoration,\nor shadow color, rewrite it to renderer tokens or remove it. Layout-only classes\nare still discouraged; inline flex/grid styles are safer and easier to review.\n\n**Keep Rough.js sparse.** `.wf-card` and `.wf-box` already render with\ntheme-safe filled backgrounds (`--wf-card`) and soft tokenized borders that work\nin both light and dark mode. Do not add `data-rough` to broad root wrappers,\ndialog shells, page panels, grid cells, or nested containers unless that single\ncontainer is the visual point. The renderer sketches the outer frame and\nstandard controls by default; use `data-rough` only for a deliberate one-off\nshape. If a mockup starts looking like stacked/overlapping sketch lines, remove\nrough targets from parent containers and let backgrounds plus spacing separate\nthe surfaces.\n\n**Use literal CSS lengths for spacing.** The `--wf-*` tokens are for colors and\nrenderer-owned visual styling, not layout spacing. Do not use guessed spacing\ntokens such as `var(--wf-space-4)`, Tailwind spacing classes, or theme spacing\nvariables inside wireframe HTML; if a token is unavailable in the Plan renderer,\npadding collapses and content hugs the border. Use explicit CSS lengths for\nlayout: `padding:16px`, `gap:12px`, `margin-top:18px`, `minmax(0,1fr)`.\n\n**Lay out with inline `style` flex/grid.** You write the real layout \u2014\n`display:flex; flex-direction:column; gap:10px; padding:16px` and so on \u2014 and the\nrenderer never repositions anything. Compose the actual product: reproduce the\ncurrent screen, then show the modification. Real labels, real counts, real dates,\nreal button text grounded in the screen you read; not lorem or gray bars.\n\n**Surface presets \u2014 match the real footprint, never default to desktop+mobile.**\nPick the `surface` that matches what the user will actually see:\n\n- `browser`: a web page that needs a browser chrome frame around it.\n- `desktop`: a full desktop app page or app shell.\n- `mobile`: a phone screen, only when the work is genuinely mobile.\n- `popover`: a small floating menu, dropdown, or inline popover.\n- `panel`: a side panel, inspector, or sidebar widget.\n\nA sidebar popover renders as a small surface, not a desktop page and a phone\nframe. Do not emit `desktop` + `mobile` variants unless responsive behavior\nactually changes the layout. For a component or widget, show one broader\napp-context frame only when placement affects understanding, then the focused\ncomponent states.\n\n**Model the actual component shell for small surfaces.** A rendered UI change\nbelongs in a wireframe; reserve `diagram` for architecture, dependency, state,\nor data-flow relationships. Popovers, dropdown menus, command palettes, and\ncontext menus use `surface: \"popover\"` unless the surrounding page placement is\nthe point of the change. Dialogs, sheets, inspectors, sidebars, and long\nproperty panels use the matching `panel` / `desktop` surface as appropriate.\nShow the real chrome: trigger or anchor when it matters, title/header row,\ntop-right actions, separators, fields, options, selected states, body content,\nand footer actions that are visible in the workflow.\n\n**Modify, don't redesign.** When the task changes an existing screen, reproduce\nthe current screen's real layout and footprint FIRST, then change only the delta\nand call it out with a single annotation. Do not restack the page into a new\nlayout. For net-new surfaces, compose from the real app shell. Inspect the\nactual app components before drawing an existing product: sidebar density,\ntoolbar actions, overflow menus, property panels, and framework chrome should\nmatch the product unless the plan intentionally changes them.\n\n**Keep product screens pure.** A product wireframe shows the app state a user\nwould actually see. Do not embed file contracts, architecture arrows, repo pills,\nmode explanations, or implementation callouts inside the screen just to explain\nthe plan. Put those in canvas annotations, a separate diagram, or the document\nbody. Secondary UI such as properties, history, sync, export, or agent controls\nshould appear where the real product would put them: an overflow popover, sheet,\npanel, or separate framework sidebar state, not a generic permanent right\ninspector unless that inspector is the actual design.\n\n**Classify mockup scope before implementation.** Before turning a plan mockup\ninto source code, decide whether each artboard represents the whole page/app\nshell, a route body inside an existing shell, or a component/sub-surface. If an\nartboard includes navigation, sidebars, auth banners, or a signup/login form,\nmap those pieces to the real shared shell/auth components instead of nesting the\nentire mockup inside the current page. When a mockup references the product's\nstandard signup/login page, find and reuse that existing implementation; do not\napproximate it from the wireframe.\n\n**Zoom in on sub-surfaces, don't redraw the page.** For a small sub-surface (a\npopover, menu, dialog, toast), show the full screen once, then add a small\nseparate artboard whose `html` contains ONLY that sub-surface \u2014 do not re-draw\nthe whole page around it, and do not scale a duplicate up. Pick the matching\n`surface` (e.g. `popover`) so the footprint is right; never widen a popover to\npage width.\n\n**Loading / skeleton states.** Set `data.skeleton: true` on the wireframe and\nfill the `html` with neutral, textless placeholder geometry \u2014 boxes and bars\nbuilt as `<div>`s with `background:var(--wf-line)` and explicit heights/widths,\nno labels or copy. The renderer drops borders, sketch, and color into the\nskeleton register automatically. Never escape to a `custom-html` document block\nto fake a loader.\n\n**Editing an existing mockup.** In hosted mode, to change one element, text, or\ncolor in an existing html mockup, do not regenerate the frame \u2014 call\n`update-visual-plan` with\n`contentPatches: [{ op: \"patch-wireframe-html\", blockId, edits: [{ find,\nreplace }] }]`. Each `find` is a unique snippet of the current html (read it\nfirst with `get-visual-plan`); set `all: true` on an edit to replace every\noccurrence. The result is re-sanitized. In local-files privacy mode, do not call\nhosted Plan tools; edit the local MDX source directly and rerun the local\ncheck/serve or verify command for `<plan-dir>`.\n\n**Treat the wireframe border as part of the visible design.** Always wrap HTML\nwireframe content in a root container with real inner padding before drawing\ncards, fields, pills, labels, or controls. Use at least 14-16px of padding,\n`box-sizing: border-box`, `height: 100%`, and `gap` between child rows on the\nroot node itself so the first row never sits flush against the screen border. Do\nnot rely on padding on a nested page section as the first visible inset; the\noutermost element must create the breathing room. Keep text away from borders:\nevery container, field, button, menu item, and annotation needs enough padding\nand line-height to read cleanly in the rendered Plan view.\n\n**For feature-cloud or abundance visuals, optimize the composition over line-by-line\nreading.** Some marketing/product sections need to feel like a large surface area\nof capability rather than a precise app workflow. In those cases, use one padded\nroot with a short headline and a dense, aesthetic cloud of short feature labels,\nchips, rings, or columns. Vary scale and opacity with tokens, cluster by meaning,\nand let many labels be glanceable rather than individually essential. Do not\nforce dozens of features into equal cards with long wrapped sentences; that\nusually creates a messy unreadable mockup.\n\n**Lay out children safely so they never collide.** Use HTML flex/grid with\n`gap`, `min-width: 0`, and sensible overflow. Avoid negative margins, absolute\npositioning, or fixed child widths that can collide when the renderer switches\nbetween light/dark, sketch/clean, or different zoom levels.\n\n**Do not wrap intentionally single-line labels.** For toolbars, tab rails,\nbreadcrumbs, chip/filter rows, branch and file names, file chips, and code\nfilenames \u2014 any deliberately single-line row \u2014 do not let long text wrap. Put\n`white-space: nowrap` on the row (and `overflow: hidden; text-overflow: ellipsis`\non the individual labels that can grow), so the wireframe demonstrates the actual\nlayout behavior instead of producing ugly stacked or vertical text. Use\nhorizontally scrollable or clipped rails for overflow.\n\n**Fill the frame; keep labels short.** Each artboard is a fixed-size surface \u2014 compose enough realistic HTML to fill it top to bottom with even vertical rhythm; never leave a large empty band. On desktop/app-shell sidebars, let the nav stack flex to fill (`flex:1`) and add any persistent bottom action/status after it so the rail reads complete in taller frames. On mobile especially, flow real rows down the whole screen (status bar, header, then list/detail content) rather than a header floating above a gap. Keep every label short enough to sit on one line within its column \u2014 shorten the copy rather than relying on the frame to absorb it (long labels wrap or clip).\n\n**Persistent chrome bars span the full frame width.** Top bars, app headers,\ntoolbars, and bottom tab/nav bars are full-width chrome, not centered content.\nLay each one out as a single flex row that fills the frame\n(`style=\"display:flex;align-items:center;width:100%\"`) and push trailing actions\nto the right edge with a flex spacer (`<div style=\"flex:1\"></div>`) between the\nleading group and the trailing group \u2014 never center a bar inside a narrow,\ncentered block, and never let it collapse to the width of its contents. In a\nBefore/After pair the bar stays full-width in BOTH states even when one state has\nfewer controls; the spacer absorbs the difference so the remaining controls hold\ntheir edge alignment instead of sliding to the center.\n\n**Pin bottom bars to the bottom of the frame.** For mobile tab bars, footers, and\nany persistent bottom action row, make the frame itself a flex column at\n`height:100%` (`style=\"display:flex;flex-direction:column;height:100%\"`), give the\nscrolling body `flex:1` so it absorbs the slack, and place the bar as the LAST\nchild of the frame (or set `margin-top:auto` on it). The bar then sits flush at\nthe bottom of the surface instead of floating directly under the content with an\nempty band beneath it.\n\n**Before / after must be comparable.** When showing a state change, preserve the\nunchanged controls in both states so the reviewer can see exactly what moved or\nappeared; do not show an added control as a generic box floating elsewhere in\nthe surface. Place the new/changed affordance where the implementation puts it \u2014\nfor example, a new `Edit with AI` action in a popover header belongs in the\ntop-right header slot, aligned with the title, not in the body or footer. Use\nthe same frame size, scale, outer padding, border radius, and visual density on\nboth sides unless the change itself alters those properties, and let the frame\nheight fit the content rather than leaving a tall empty lower half.\n\n**Name the states with the column header, never inside the frame.** For\ndocument-body wireframes (recaps), put the two\nstates in a `columns` block and set each column's `label` to `Before` and\n`After` \u2014 the renderer draws that label as an `h4` heading above each frame. Do\nNOT bake a `Before`/`After` pill, title, or heading into the wireframe `html`: a\nlabel placed inside reads as part of the product UI, lands in a random corner,\nand clutters the comparison. The column header is the one and only place the\nstate name belongs. On a canvas, place the two state artboards as neighbors with\nframe labels \u2014 never encode Before/After inside the html.\n\n**Let the surface choose side-by-side vs. stacked.** For document-body\nwireframes (recaps), the `columns` renderer lays\nnarrow surfaces (`mobile`, `popover`, `panel`) out side by side, and\nautomatically stacks wide surfaces (`desktop`, `browser`) vertically at full\ndocument width so a large frame is never crushed into a half-width column and\ncropped. Author both wireframes with the real `surface` and the matching\n`Before`/`After` column labels; do not hand-stack the pair into separate\ntop-level wireframes or duplicate the state name as body content.\n\n**Good example \u2014 a contacts list, surface `browser`.** A small, real screen\ncomposed from the helper classes and tokens, layout in inline flex, no fonts or\nhex colors:\n\n```html\n<div\n style=\"display:flex;flex-direction:column;gap:12px;padding:16px;height:100%\"\n>\n <div style=\"display:flex;align-items:center;justify-content:space-between\">\n <h1>Contacts</h1>\n <button class=\"primary\">New contact</button>\n </div>\n <div style=\"display:flex;gap:6px\">\n <span class=\"wf-pill accent\">All 128</span>\n <span class=\"wf-pill\">Favorites</span>\n <span class=\"wf-pill\">Archived</span>\n </div>\n <div\n class=\"wf-card\"\n style=\"display:flex;flex-direction:column;gap:0;padding:0\"\n >\n <div\n style=\"display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1.4px solid var(--wf-line)\"\n >\n <div\n style=\"width:32px;height:32px;border-radius:999px;background:var(--wf-accent-soft)\"\n ></div>\n <div style=\"flex:1\">\n <strong>Jane Cooper</strong><br /><small>jane@acme.co</small>\n </div>\n <span class=\"wf-pill\">Lead</span>\n </div>\n <div style=\"display:flex;align-items:center;gap:10px;padding:10px 12px\">\n <div\n style=\"width:32px;height:32px;border-radius:999px;background:var(--wf-accent-soft)\"\n ></div>\n <div style=\"flex:1\">\n <strong>Marcus Lee</strong><br /><small>marcus@globex.io</small>\n </div>\n <span class=\"wf-pill\">Customer</span>\n </div>\n </div>\n</div>\n```\n\n<!-- SHARED-CORE:wireframe-quality END -->\n";
9
+ export declare const WIREFRAME_REFERENCE_MD = "# HTML wireframe quality \u2014 single source of truth\n\nThis file is the canonical quality bar for HTML wireframes / `<Screen>` /\n`WireframeBlock` content, shared word for word by `/visual-plan` and\n`/visual-recap`. Read it in full before authoring ANY wireframe; do not\nauthor wireframes from memory or paraphrase these rules per command.\n\n<!-- SHARED-CORE:wireframe-quality START -->\n\n**A wireframe is an HTML mockup. The renderer owns the look; you write the\ncontent.** Set `data.html` to a self-contained, semantic HTML fragment of the\nscreen and set `data.surface`. The renderer owns the surface footprint/aspect,\nthe dark/light theme, the hand-drawn font, and the rough.js sketch overlay \u2014 you\nnever write `<html>`/`<body>`/`<script>`/`<style>` tags or any\nwidth/height/coordinates. You write real HTML layout and real product\ncontent; the renderer styles and roughens it.\n\n**A wireframe block's data is an HTML screen plus a surface:**\n\n```json\n{\n \"surface\": \"browser\",\n \"html\": \"<div style=\\\"display:flex;flex-direction:column;gap:10px;padding:16px;height:100%\\\"><h1>Sign in</h1><p class=\\\"wf-muted\\\">Use your work email to continue.</p><div class=\\\"wf-card\\\" style=\\\"display:flex;flex-direction:column;gap:10px\\\"><label>Email<input value=\\\"jane@acme.co\\\" /></label><label>Password<input value=\\\"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\\\" /></label><label style=\\\"display:flex;align-items:center;gap:8px\\\"><input type=\\\"checkbox\\\" checked /> Remember me</label><button class=\\\"primary\\\">Sign in</button></div><a href=\\\"#\\\">Forgot password?</a></div>\"\n}\n```\n\n**Write PLAIN semantic HTML and let the renderer style it.** Bare elements\n(`h1`/`h2`/`h3`, `p`, `button`, `input`, `<input type=\"checkbox\">`, `a`, `hr`)\nare auto-themed \u2014 no classes needed. Helper classes carry the rest:\n\n- `.wf-card` / `.wf-box` \u2014 a bordered, padded container (a panel, a list item).\n- `.wf-pill` / `.wf-chip` \u2014 a rounded tag or filter; add `.accent`\n (`<span class=\"wf-pill accent\">`) for the accent-filled variant.\n- `.wf-muted` \u2014 secondary/muted text (or use `<small>`).\n- `button.primary` or any element with `[data-primary]` \u2014 the accent-filled\n primary button.\n\n**No decorative shadows around mockups.** Do not put `box-shadow`, `filter:\ndrop-shadow(...)`, Tailwind `shadow-*` classes, or other fake depth effects on a\nwireframe frame, root container, `.wf-card` / `.wf-box`, or canvas artboard.\nMockups should read as flat, bordered surfaces; use spacing, borders, labels,\nand annotations for separation. Only show a shadow when the real product UI\nalready has that shadow and it is essential to the change being reviewed.\n\n**Use renderer icons, not visible icon words.** For icon-only buttons or leading\nicons inside fields, chips, menu items, and toolbars, write an empty marker such\nas `<span data-icon=\"mail\" aria-label=\"Email\"></span>` or\n`<i data-icon=\"lock\"></i>`. The renderer replaces it with a Tabler-style SVG and\nthe `.wf-icon` class sizes it to the surrounding text. Supported names and\naliases: `mail`/`email`, `lock`/`password`, `search`, `plus`/`add`, `x`/`close`,\n`check`, `chevronDown`, `chevronUp`, `chevronLeft`, `chevronRight`, `dots`/`more`,\n`chevron`/`caret`/`dropdown` (down chevron), `user`, `settings`, `calendar`,\n`bell`, `send`, `edit`, `arrowLeft`, and `arrowRight`. Do not put visible words\nlike \"email\", \"lock\", \"search\", \"chevron\", or \"more\" where the product UI would\nshow an icon; use text only when it is a real label a user would read.\n\n**Use the `--wf-*` tokens for any custom color, never hex.** The renderer flips\nthese on light/dark, so reading them is what keeps a mockup correct in both\nthemes. For any inline border, background, or text color, reference a token:\n`style=\"border:1.4px solid var(--wf-line)\"`. The tokens are `--wf-ink` (text),\n`--wf-muted` (secondary text), `--wf-line` (borders/dividers), `--wf-paper`\n(page background), `--wf-card` (container surface), `--wf-accent` /\n`--wf-accent-fg` / `--wf-accent-soft` (brand action), `--wf-warn`, `--wf-ok`,\nand `--wf-radius`. Never hard-code a hex color and never set `font-family` \u2014 the\nrenderer owns the sketch/clean font.\n\n**Never use host/Tailwind theme classes in wireframe HTML.** Classes such as\n`bg-white`, `bg-zinc-50`, `bg-slate-950`, `text-zinc-950`,\n`text-slate-400`, `border-zinc-200`, `hover:bg-slate-800`, `shadow-xl`,\nor arbitrary color utilities like `bg-[#fff]` leak the host app's CSS into the\nmockup and can make dark-mode canvas frames unreadable. Use bare semantic\nelements, `.wf-*` helper classes, and `--wf-*` color tokens instead. Before\npublishing, scan every wireframe `class` and `style` attribute: if a class sets\nbackground, text, border, ring, fill, stroke, gradient, placeholder, decoration,\nor shadow color, rewrite it to renderer tokens or remove it. Layout-only classes\nare still discouraged; inline flex/grid styles are safer and easier to review.\n\n**Keep Rough.js sparse.** The renderer sketches the outer frame, standard\n`.wf-*` primitives, controls, and inline border dividers by default. Do not add\n`data-rough` to broad root wrappers, dialog shells, page panels, grid cells, or\nnested containers unless that single container is the visual point. Use\n`data-rough` only for a deliberate one-off shape. If a mockup starts looking\nlike stacked/overlapping sketch lines, remove rough targets from parent\ncontainers and let backgrounds plus spacing separate the surfaces.\n\n**Use literal CSS lengths for spacing.** The `--wf-*` tokens are for colors and\nrenderer-owned visual styling, not layout spacing. Do not use guessed spacing\ntokens such as `var(--wf-space-4)`, Tailwind spacing classes, or theme spacing\nvariables inside wireframe HTML; if a token is unavailable in the Plan renderer,\npadding collapses and content hugs the border. Use explicit CSS lengths for\nlayout: `padding:16px`, `gap:12px`, `margin-top:18px`, `minmax(0,1fr)`.\n\n**Lay out with inline `style` flex/grid.** You write the real layout \u2014\n`display:flex; flex-direction:column; gap:10px; padding:16px` and so on \u2014 and the\nrenderer never repositions anything. Compose the actual product: reproduce the\ncurrent screen, then show the modification. Real labels, real counts, real dates,\nreal button text grounded in the screen you read; not lorem or gray bars.\n\n**Surface presets \u2014 match the real footprint, never default to desktop+mobile.**\nPick the `surface` that matches what the user will actually see:\n\n- `browser`: a web page that needs a browser chrome frame around it.\n- `desktop`: a full desktop app page or app shell.\n- `mobile`: a phone screen, only when the work is genuinely mobile.\n- `popover`: a small floating menu, dropdown, or inline popover.\n- `panel`: a side panel, inspector, or sidebar widget.\n\nA sidebar popover renders as a small surface, not a desktop page and a phone\nframe. Do not emit `desktop` + `mobile` variants unless responsive behavior\nactually changes the layout. For a component or widget, show one broader\napp-context frame only when placement affects understanding, then the focused\ncomponent states.\n\n**Model the actual component shell for small surfaces.** A rendered UI change\nbelongs in a wireframe; reserve `diagram` for architecture, dependency, state,\nor data-flow relationships. Popovers, dropdown menus, command palettes, and\ncontext menus use `surface: \"popover\"` unless the surrounding page placement is\nthe point of the change. Dialogs, sheets, inspectors, sidebars, and long\nproperty panels use the matching `panel` / `desktop` surface as appropriate.\nShow the real chrome: trigger or anchor when it matters, title/header row,\ntop-right actions, separators, fields, options, selected states, body content,\nand footer actions that are visible in the workflow.\n\n**Modify, don't redesign.** When the task changes an existing screen, reproduce\nthe current screen's real layout and footprint FIRST, then change only the delta\nand call it out with a single annotation. Do not restack the page into a new\nlayout. For net-new surfaces, compose from the real app shell. Inspect the\nactual app components before drawing an existing product: sidebar density,\ntoolbar actions, overflow menus, property panels, and framework chrome should\nmatch the product unless the plan intentionally changes them.\n\n**Keep product screens pure.** A product wireframe shows the app state a user\nwould actually see. Do not embed file contracts, architecture arrows, repo pills,\nmode explanations, or implementation callouts inside the screen just to explain\nthe plan. Put those in canvas annotations, a separate diagram, or the document\nbody. Secondary UI such as properties, history, sync, export, or agent controls\nshould appear where the real product would put them: an overflow popover, sheet,\npanel, or separate framework sidebar state, not a generic permanent right\ninspector unless that inspector is the actual design.\n\n**Classify mockup scope before implementation.** Before turning a plan mockup\ninto source code, decide whether each artboard represents the whole page/app\nshell, a route body inside an existing shell, or a component/sub-surface. If an\nartboard includes navigation, sidebars, auth banners, or a signup/login form,\nmap those pieces to the real shared shell/auth components instead of nesting the\nentire mockup inside the current page. When a mockup references the product's\nstandard signup/login page, find and reuse that existing implementation; do not\napproximate it from the wireframe.\n\n**Zoom in on sub-surfaces, don't redraw the page.** For a small sub-surface (a\npopover, menu, dialog, toast), show the full screen once, then add a small\nseparate artboard whose `html` contains ONLY that sub-surface \u2014 do not re-draw\nthe whole page around it, and do not scale a duplicate up. Pick the matching\n`surface` (e.g. `popover`) so the footprint is right; never widen a popover to\npage width.\n\n**Loading / skeleton states.** Set `data.skeleton: true` on the wireframe and\nfill the `html` with neutral, textless placeholder geometry \u2014 boxes and bars\nbuilt as `<div>`s with `background:var(--wf-line)` and explicit heights/widths,\nno labels or copy. The renderer drops borders, sketch, and color into the\nskeleton register automatically. Never escape to a `custom-html` document block\nto fake a loader.\n\n**Editing an existing mockup.** In hosted mode, to change one element, text, or\ncolor in an existing html mockup, do not regenerate the frame \u2014 call\n`update-visual-plan` with\n`contentPatches: [{ op: \"patch-wireframe-html\", blockId, edits: [{ find,\nreplace }] }]`. Each `find` is a unique snippet of the current html (read it\nfirst with `get-visual-plan`); set `all: true` on an edit to replace every\noccurrence. The result is re-sanitized. In local-files privacy mode, do not call\nhosted Plan tools; edit the local MDX source directly and rerun the local\ncheck/serve or verify command for `<plan-dir>`.\n\n**Treat the wireframe border as part of the visible design.** Always wrap HTML\nwireframe content in a root container with real inner padding before drawing\ncards, fields, pills, labels, or controls. Use at least 14-16px of padding,\n`box-sizing: border-box`, `height: 100%`, and `gap` between child rows on the\nroot node itself so the first row never sits flush against the screen border. Do\nnot rely on padding on a nested page section as the first visible inset; the\noutermost element must create the breathing room. Keep text away from borders:\nevery container, field, button, menu item, and annotation needs enough padding\nand line-height to read cleanly in the rendered Plan view.\n\n**For feature-cloud or abundance visuals, optimize the composition over line-by-line\nreading.** Some marketing/product sections need to feel like a large surface area\nof capability rather than a precise app workflow. In those cases, use one padded\nroot with a short headline and a dense, aesthetic cloud of short feature labels,\nchips, rings, or columns. Vary scale and opacity with tokens, cluster by meaning,\nand let many labels be glanceable rather than individually essential. Do not\nforce dozens of features into equal cards with long wrapped sentences; that\nusually creates a messy unreadable mockup.\n\n**Lay out children safely so they never collide.** Use HTML flex/grid with\n`gap`, `min-width: 0`, and sensible overflow. Avoid negative margins, absolute\npositioning, or fixed child widths that can collide when the renderer switches\nbetween light/dark, sketch/clean, or different zoom levels.\n\n**Do not wrap intentionally single-line labels.** For toolbars, tab rails,\nbreadcrumbs, chip/filter rows, branch and file names, file chips, and code\nfilenames \u2014 any deliberately single-line row \u2014 do not let long text wrap. Put\n`white-space: nowrap` on the row (and `overflow: hidden; text-overflow: ellipsis`\non the individual labels that can grow), so the wireframe demonstrates the actual\nlayout behavior instead of producing ugly stacked or vertical text. Use\nhorizontally scrollable or clipped rails for overflow.\n\n**Fill the frame; keep labels short.** Each artboard is a fixed-size surface \u2014 compose enough realistic HTML to fill it top to bottom with even vertical rhythm; never leave a large empty band. On desktop/app-shell sidebars, let the nav stack flex to fill (`flex:1`) and add any persistent bottom action/status after it so the rail reads complete in taller frames. On mobile especially, flow real rows down the whole screen (status bar, header, then list/detail content) rather than a header floating above a gap. Keep every label short enough to sit on one line within its column \u2014 shorten the copy rather than relying on the frame to absorb it (long labels wrap or clip).\n\n**Persistent chrome bars span the full frame width.** Top bars, app headers,\ntoolbars, and bottom tab/nav bars are full-width chrome, not centered content.\nLay each one out as a single flex row that fills the frame\n(`style=\"display:flex;align-items:center;width:100%\"`) and push trailing actions\nto the right edge with a flex spacer (`<div style=\"flex:1\"></div>`) between the\nleading group and the trailing group \u2014 never center a bar inside a narrow,\ncentered block, and never let it collapse to the width of its contents. In a\nBefore/After pair the bar stays full-width in BOTH states even when one state has\nfewer controls; the spacer absorbs the difference so the remaining controls hold\ntheir edge alignment instead of sliding to the center.\n\n**Pin bottom bars to the bottom of the frame.** For mobile tab bars, footers, and\nany persistent bottom action row, make the frame itself a flex column at\n`height:100%` (`style=\"display:flex;flex-direction:column;height:100%\"`), give the\nscrolling body `flex:1` so it absorbs the slack, and place the bar as the LAST\nchild of the frame (or set `margin-top:auto` on it). The bar then sits flush at\nthe bottom of the surface instead of floating directly under the content with an\nempty band beneath it.\n\n**Before / after must be comparable.** When showing a state change, preserve the\nunchanged controls in both states so the reviewer can see exactly what moved or\nappeared; do not show an added control as a generic box floating elsewhere in\nthe surface. Place the new/changed affordance where the implementation puts it \u2014\nfor example, a new `Edit with AI` action in a popover header belongs in the\ntop-right header slot, aligned with the title, not in the body or footer. Use\nthe same frame size, scale, outer padding, border radius, and visual density on\nboth sides unless the change itself alters those properties, and let the frame\nheight fit the content rather than leaving a tall empty lower half.\n\n**Name the states with the column header, never inside the frame.** For\ndocument-body wireframes (recaps), put the two\nstates in a `columns` block and set each column's `label` to `Before` and\n`After` \u2014 the renderer draws that label as an `h4` heading above each frame. Do\nNOT bake a `Before`/`After` pill, title, or heading into the wireframe `html`: a\nlabel placed inside reads as part of the product UI, lands in a random corner,\nand clutters the comparison. The column header is the one and only place the\nstate name belongs. On a canvas, place the two state artboards as neighbors with\nframe labels \u2014 never encode Before/After inside the html.\n\n**Let the surface choose side-by-side vs. stacked.** For document-body\nwireframes (recaps), the `columns` renderer lays\nnarrow surfaces (`mobile`, `popover`, `panel`) out side by side, and\nautomatically stacks wide surfaces (`desktop`, `browser`) vertically at full\ndocument width so a large frame is never crushed into a half-width column and\ncropped. Author both wireframes with the real `surface` and the matching\n`Before`/`After` column labels; do not hand-stack the pair into separate\ntop-level wireframes or duplicate the state name as body content.\n\n**Good example \u2014 a contacts list, surface `browser`.** A small, real screen\ncomposed from the helper classes and tokens, layout in inline flex, no fonts or\nhex colors:\n\n```html\n<div\n style=\"display:flex;flex-direction:column;gap:12px;padding:16px;height:100%\"\n>\n <div style=\"display:flex;align-items:center;justify-content:space-between\">\n <h1>Contacts</h1>\n <button class=\"primary\">New contact</button>\n </div>\n <div style=\"display:flex;gap:6px\">\n <span class=\"wf-pill accent\">All 128</span>\n <span class=\"wf-pill\">Favorites</span>\n <span class=\"wf-pill\">Archived</span>\n </div>\n <div\n class=\"wf-card\"\n style=\"display:flex;flex-direction:column;gap:0;padding:0\"\n >\n <div\n style=\"display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1.4px solid var(--wf-line)\"\n >\n <div\n style=\"width:32px;height:32px;border-radius:999px;background:var(--wf-accent-soft)\"\n ></div>\n <div style=\"flex:1\">\n <strong>Jane Cooper</strong><br /><small>jane@acme.co</small>\n </div>\n <span class=\"wf-pill\">Lead</span>\n </div>\n <div style=\"display:flex;align-items:center;gap:10px;padding:10px 12px\">\n <div\n style=\"width:32px;height:32px;border-radius:999px;background:var(--wf-accent-soft)\"\n ></div>\n <div style=\"flex:1\">\n <strong>Marcus Lee</strong><br /><small>marcus@globex.io</small>\n </div>\n <span class=\"wf-pill\">Customer</span>\n </div>\n </div>\n</div>\n```\n\n<!-- SHARED-CORE:wireframe-quality END -->\n";
10
10
  export declare const CANVAS_REFERENCE_MD = "# Canvas & artboard placement \u2014 single source of truth\n\nThis file is the canonical guide for how the visual-plan canvas works: artboard\nplacement, lane layout, annotations, patching, and the legacy kit tree. Read it\nin full before authoring or editing any canvas/artboard content; do not author\ncanvas layouts from memory or paraphrase these rules per mode.\n\n<!-- SHARED-CORE:canvas-surface START -->\n\n**The coordinate rule.** The `surface` locks each artboard's footprint and\naspect \u2014 never set artboard width/height and never use coordinates inside the\nwireframe HTML; board-level artboard `x`/`y` IS allowed when it creates clear\nlanes. Let canvas auto-placement handle simple one-row boards.\n\n**Lay out mixed canvases in lanes.** When a canvas contains broad browser /\ndesktop frames plus compact `mobile`, `popover`, or `panel` surfaces, do not put\neverything in one horizontal strip. Use board-level artboard `x`/`y` to reserve\nlanes with generous empty space: main flow on one row, compact surfaces in their\nown column or row, and loading/error states in a lower row. Keep at least 96px\nbetween rendered artboard rectangles plus room for annotation gutters; when a\nbroad browser/desktop frame sits beside a compact panel/popover, leave at least\n160px so frame borders, labels, and hover controls never touch. Connect only\nneighboring steps; never draw a long connector that skips across unrelated\nframes. Connector labels must sit in open canvas space. If the label would touch\nor cross either artboard, remove the label and explain the transition with a\nnearby annotation instead. Before handoff, inspect the top canvas at default zoom\nand move any frame whose label, connector, or annotation crosses another frame.\n\n**Board-unit spacing defaults.** The canvas coordinate system uses approximately 2 board units per screen pixel. `browser` frames occupy roughly 700 \u00D7 600 board units; `desktop` frames roughly 900 \u00D7 700 board units. Apply these minimum x/y gaps when placing frames explicitly \u2014 any less and frames will touch or overlap:\n\n- x-gap between `browser` frames: **\u2265 1100** (700-unit frame + 400-unit gutter)\n- x-gap between `desktop` frames: **\u2265 1300** (900-unit frame + 400-unit gutter)\n- y-gap between rows of any surface: **\u2265 1400** (includes frame height + section header + buffer)\n\nWhen in doubt, use larger values \u2014 the canvas auto-zooms to fit everything.\n\n**Canvas annotations are designer notes on the artboard.** When a top canvas is\npresent, sprinkle design-review notes near the frames they explain: a short\nheading, supporting text, and bullets \u2014 plain text layers, never bordered or\nshadowed cards, and never a box around a frame. The renderer spaces notes away\nfrom frames, so place each note by the frame it describes. Use an arrow only to\npoint at one specific control or transition; for a broad frame-level note, write\ntext beside the frame with no connector. Connectors are for real sequences only \u2014\nnever fake \"Step 1 \u2192 Step 2\" lines between independent states.\n\n**Do not create overlapping annotations.** Anchor each ordinary note to the\nframe it explains with `targetId` + `placement` (top/right/bottom/left), and\nomit `type` or use `type: \"note\"`. The renderer parks notes in a gutter beside\nthe frame and lays them out automatically. Do not use `type: \"callout\"`,\n`type: \"text\"`, `type: \"arrow\"`, x/y, or points for ordinary notes; those are\nfreeform review-markup layers and must be reserved for intentional markup in\nopen canvas space. Reserve arrows for a note that must point at one specific\ncontrol inside a frame; a note that simply sits beside its frame needs no arrow.\n\n**Patching.** Edit one wireframe, canvas annotation, diagram, or block with targeted `contentPatches`\n(for example `patch-wireframe-html`, `patch-diagram-html`, `update-block`,\n`replace-blocks`, `update-canvas-annotation`) rather\nthan regenerating the whole plan. `contentPatches` are part of the public MCP\naction schema, so Claude Code, Codex, Cursor, and other hosts can make surgical\nedits. If an agent is working from exported source files, use\n`read-visual-plan-source` / `patch-visual-plan-source`: `plan.mdx` holds\nfrontmatter plus markdown/document blocks, `canvas.mdx` holds\n`<DesignBoard>/<Section>/<Artboard>/<Screen>/<Annotation>/<Connector>`, and the\npatch action normalizes the MDX back into the same JSON runtime model. JSON is\nthe canonical runtime shape; MDX is the repo-friendly authoring/export surface.\nIn the browser, humans edit `rich-text` prose inline; agents should still use\n`update-rich-text` content patches or source patches for prose, and use\ncomments/structured patches for canvas, artboard, wireframe, and diagram edits.\nNever send a partial top-level `content` object as a shortcut to add a canvas,\nframe, or block: `content` is a full structured replacement, so omitted blocks\nor surfaces can disappear. If a full replacement is truly unavoidable, read the\ncomplete source/JSON first, include every existing block and surface in the new\npayload, and verify the source/export immediately after the update.\n\n**Never emit a titled artboard with no interior wireframe content.** Every artboard\nyou place on the canvas must carry an `html` wireframe or reference a wireframe\nblock via `blockId`; when using `blockId`, the referenced `wireframe` /\n`legacy-wireframe` block must remain in the plan. If you remove a duplicate\nwireframe from the document body, first move its `data` inline onto the\ncorresponding `content.canvas.frames[*].wireframe` / `legacyWireframe`. A\nlabel-only frame or a frame pointing at a deleted block renders empty and is\nrejected at parse time. If you only have a title, write it as a section header or\nannotation, not an empty artboard.\n\n**UI mockups belong in the top visual review area.** Static UI/product visuals\nlive on the canvas; multi-step UI flows get both canvas wireframes and a\nprototype. When the user asks for a mockup, UI state, loading state, layout,\nscreen, or visual comparison, make the canvas the primary home for that static\nvisual. When the user asks for a prototype or the plan contains a sequence the\nreviewer must feel, keep the canvas artboards and add `content.prototype` so the\ntop surface shows Wireframes / Prototype tabs. Architecture/code diagrams stay\ninline in the document (the SKILL.md Visual Surface Choice section owns that\nrule) unless the user explicitly asks for a spatial board. Document blocks\ncan explain, compare, or map implementation, but they should not host the\nprimary UI mockup or prototype just because `custom-html`, screenshots, or prose\nare easier to produce. If the canvas/prototype surface cannot represent the\nrequested UI fidelity, still keep the closest top-surface representation and\ncall out or extend the needed renderer capability. A skeleton/loading mockup\nalso lives in a canvas artboard \u2014 never move a mockup out of the canvas.\n\n**Storyboards are canvas artifacts, not document diagrams.** When the requested\noutput is a product flow, onboarding journey, \"light storyboard\", or canvas\nwireframe, author the flow as multiple top-canvas artboards with real screen\ncontent and neighboring connectors. Keep document-body `diagram` blocks for\narchitecture and mechanics that are not themselves user-visible screens. A\nstoryboard made from a single inline HTML diagram is the wrong surface.\n\nFor abstract product concepts, use the canvas to create the first \"I get it\"\nmoment: one real app state near the top showing how the concept appears to a\nuser, followed by separate annotations or diagrams for mechanics. Do not make\nthe first artboard a hybrid of app UI and architecture notes; the app screen\nshould be inspectable as product UI on its own.\n\n**Legacy kit tree.** Older plans set a `screen` array of `{ el, ...props }` kit\nnodes instead of `html`; the renderer still accepts and displays it so saved\nplans round-trip, but new plans emit `html`. Do not author fresh kit-tree\nscreens, and do not put nested kit components such as `<FrameScreen>`, `<Card>`,\n`<Row>`, `<Title>`, or `<Btn>` inside a canvas `<Screen>`. A new canvas artboard\nwith kit-tree children is a defect: replace it with\n`<Screen surface=\"...\" html={...} />` using the HTML wireframe rules. The HTML\npath is the one that gets the renderer-owned surface sizing, theme tokens,\nsketch/clean toggle, and safe text layout used by good document-body\nwireframes. Likewise, old or imported plans may carry coordinate-based regions\nor free-float x/y on notes; those are legacy escape hatches the renderer still\nshows but you must never produce. The gutter parks notes by `targetId` +\n`placement`, and the coordinate rule at the top of this file governs all\nnew-plan placement.\n\n<!-- SHARED-CORE:canvas-surface END -->\n";
11
11
  export declare const DOCUMENT_QUALITY_REFERENCE_MD = "# Plan document quality \u2014 single source of truth\n\nThis file is the canonical quality bar for the plan document below the canvas:\nhow it reads, which blocks to use, how open questions are surfaced, and the\npre-handoff check. Read it in full before authoring the plan document; it is the\nquality bar. Do not write the document from memory or paraphrase these rules per\nmode.\n\n<!-- SHARED-CORE:document-quality START -->\n\n**The document is a serious technical plan, not marketing.** Write it the way a\nstrong Claude or Codex implementation plan reads: outcome-first, prose-first,\nself-contained, and specific. State the objective and what \"done\" means, the\nscope and non-goals, the proposed approach with the key decisions and their\nrationale, ordered steps that name real files, symbols, actions, and data\nshapes, the risks, and a closing verification step (tests, build, or a checkable\nbehavior). Replace vague prose with specifics; never ship a step like \"make it\nwork.\" No hero art, gradients, logos, nav bars, slogans, value props, giant\nlanding-page headings, or marketing cards unless the user explicitly asks.\n\n**Every published plan must stand alone.** Even when the agent is revising an\nexisting plan, the output is a plan to do the work, not a changelog of the\nconversation. Do not write phrases like \"preserve the previous plan\", \"do not\ndrop the old idea\", \"as discussed above\", \"this revision\", \"unlike the prior\nversion\", or \"correction from the earlier plan\". Fold the right decisions into\nthe plan as normal objective, architecture, scope, and roadmap prose. A reviewer\nwho opens the plan from a link with no chat history should understand it. Avoid\nnegative framing that only makes sense against absent context (\"not the old\nmode\", \"not just X\") unless the contrast is defined in the plan and genuinely\nhelps; state the positive model directly.\n\n**Make abstract plans instantly legible.** If the idea is broad, strategic, or\nintended for a third-party reviewer, put one concrete product snapshot near the\ntop before dense architecture, mode tables, manifests, or roadmaps. For\nUI-capable concepts, that snapshot is usually a top-canvas app state plus a\nshort paragraph that says what the user sees and what changes under the hood.\nThen put mechanics, data flow, sync boundaries, and implementation detail in\nseparate diagrams or document sections.\n\n**Preserve the user's level of abstraction.** A motivating use case is not\nautomatically the architecture. When the prompt describes a broader framework,\nproduct mode, or reusable primitive, separate the reusable core from specific\napps, providers, customers, scripts, or launch examples. Use the concrete\nexample to make the plan understandable, then make clear which parts are core,\nwhich are app-specific adapters, and which are future examples.\n\n**When top visuals exist, they and the document never duplicate each other.**\nFor UI work, the UI story lives in the top visual surface: canvas artboards for\nstatic inspection, plus prototype tabs when the flow should be functional. The\ndocument carries the technical depth the visuals cannot show \u2014 concrete\nfile/symbol maps, API and data contracts, code snippets, migration or\nimplementation phases, risks, and validation. For architecture/code reviews,\ninvert that: the document is the visual surface, and each recommendation\ncarries its own nearby inline `diagram` / `data-model` block plus file\nevidence (the `diagram` bullet below owns how to author those diagrams).\nRepeat a wireframe in the document only for a genuinely new detail view or\ncomparison. Skip the visual surface entirely for non-visual work and write a\nclean rich document. For a simple binary UI visual choice, show the two\ndirections in the canvas only; do not repeat the same options as body\nwireframes or prose. Put the actual choice in the bottom \"Open Questions\" form.\n\n**Use the right block, and make it carry substance.** For the authoritative,\nmachine-checked list of block types and their data schemas, call `get-plan-blocks`\n\u2014 it returns the live registry vocabulary (type, MDX tag, placement, key fields)\nso you never emit a block the editor cannot render or round-trip:\n\n- `rich-text` for plan prose with real bold/italic/code/links and nested lists.\n- `annotated-code` for the file map: when a load-bearing file is worth\n highlighting, prefer the annotated walkthrough over a bare `code` block \u2014 carry\n the real, syntax-highlighted code AND anchor short margin notes to the lines\n that actually change (the new action, the changed schema, the wiring point), so\n the reader sees what matters and why instead of code for code's sake. Each\n annotation is `{ lines: \"12\" | \"12-18\"; label?; note }`; keep a few high-signal\n notes per file, not one per line. Highlight only the files worth reading; never\n an exhaustive list of every touched file, and never a prose-only description of\n a file. Drop to a plain `code` block only for a throwaway snippet with nothing\n to call out. When more than one file matters, group the blocks in a vertical\n `tabs` block (the standard tab primitive) rather than a bespoke container. If\n the exact code is unknown, show the smallest plausible planned shape or a\n commented stub naming what to fill in. (`code-tabs` and `implementation-map`\n are legacy: their renderers stay for old plans, but do not author new ones.)\n- For a decision: if the reviewer must still pick between a genuinely-open\n either/or, put it in the bottom Open Questions `question-form` as a `single`\n question \u2014 one option per real alternative, each with a short detail and\n `recommended: true` on the one you would choose; do not also restate the same\n choice elsewhere. If you have already committed to an approach, state it as\n settled prose or a `callout` with `tone=\"decision\"`, optionally with a\n `columns` block for a side-by-side comparison of the options you weighed \u2014 not\n as a confusing mid-document form for a question you have already answered.\n- `columns` for side-by-side before/after or current/target comparisons where\n each side needs real nested blocks; label the columns clearly and avoid\n stacking comparison blocks vertically when parallel reading is the point.\n- `diagram` for two-dimensional architecture, dependency, data-flow, or state\n relationships, only when it clarifies something real. Prefer standard\n two-dimensional layouts \u2014 paired before/after panels, layered diagrams,\n swimlanes, dependency maps, matrices, or grouped regions; do not default to\n left-to-right chains, and use a line only when the relationship is truly a\n sequence. Do not use a body `diagram` as the primary artifact for a requested\n product canvas, light storyboard, UI flow, screen flow, or wireframe; those\n belong in the top canvas as artboards with `Screen` wireframes first. Use\n diagrams below that canvas only for architecture, data flow, or implementation\n mechanics. For architecture/code\n diagrams, prefer `data.html` / `data.css` with semantic HTML and inline SVG so\n the diagram can use panels, layers, matrices, arrows, annotations, and\n responsive layout directly. Author diagram HTML with renderer-owned primitives\n like `.diagram-panel`, `.diagram-card`, `.diagram-node`, `.diagram-box`,\n `.diagram-pill`, `.diagram-muted`, and `[data-rough]`; they map to the plan's\n Tailwind theme variables through `--wf-ink`, `--wf-muted`, `--wf-line`,\n `--wf-paper`, `--wf-card`, `--wf-accent`, `--wf-accent-soft`, `--wf-warn`, and\n `--wf-ok`, and switch to Excalifont plus rough.js outlines in sketchy mode. Do not\n set `font-family` and do not hard-code hex, rgb, or hsl colors in diagram HTML\n or CSS. Leave room for the sketch font: keep labels short, give nodes generous\n width, and place boundary/annotation labels in unused space instead of over\n nodes; labels must not overlap nodes, connectors, or each other. For small\n text/SVG changes to an existing HTML diagram, use `patch-diagram-html` with a\n unique `find`/`replace` snippet instead of resending the whole `data.html`\n string. Use legacy `nodes` / `edges` only for small previews or truly\n sequential flows. In architecture/code plans, prefer a repeated section rhythm:\n recommendation title, confidence and category badges, code-path evidence, a\n local before/after or current/target spatial diagram, then concise\n Problem/Solution/Why text.\n- `tabs` for multiple states, directions, or comparisons. A tab that reveals\n only prose usually means the plan is under-specified \u2014 include a relevant\n visual unless the tab is intentionally document-only.\n- `table`, `checklist`, `callout` for scannable structure.\n\n**Open questions live at the bottom as a form when answers would change the\nplan.** Surface answerable unresolved decisions in a final `question-form`\nblock titled \"Open Questions\" so the renderer presents it as a distinct section.\nThat bottom form is the ONLY place that enumerates the open questions: never add\na second \"Open Questions\" heading, list, or recap of the same questions earlier\nin the document. A one-line pointer in the overview prose (\"a few decisions are\nstill open \u2014 see Open Questions below\") is fine, but do not reproduce the\nquestion list or a parallel questions/decisions section above it.\nUse `single` or `multi` for clear choices, `freeform` for constraints,\n`recommended: true` for the default you would pick, and option `wireframe` /\n`diagram` previews only when the options are not already visible in the top\ncanvas. `single` and `multi` questions always render a write-in field so a\nreviewer can answer with a custom option \u2014 never add an explicit \"Other\" option\nyourself; set `allowOther: false` only when a free-text answer makes no sense.\nKeep non-answerable assumptions or risks as concise `callout` blocks in\nthe relevant section. Never bury a questions/decisions wall inside the plan\nnarrative, and never ask the same question twice.\n\nFor complex plans, do not end without an open-question audit. If architecture,\nscope, UX, data shape, rollout, provider mapping, or ownership still depends on\na choice, either commit to a recommendation with rationale or add it to the\nbottom form with a recommended default. A complex plan with no open questions is\nfine only when every meaningful decision has been explicitly made.\n\n**Verification must exercise the real workflow.** The final verification section\nshould go beyond typecheck/unit tests when the plan changes UI, local files,\nsync, providers, browser behavior, or multi-app flows. Include at least one\nend-to-end smoke that matches the user journey, such as a fresh repo/folder,\nreal manifest or data fixture, browser interaction, save/sync action, and an\non-disk or database assertion. Name the command or manual browser path when it\nis known.\n\n**`custom-html` is a bounded escape hatch only** \u2014 a single complete fragment\ninside a block, never `html`/`head`/`body`/`script` tags, never a generic\nplaceholder, density demo, or proof that custom HTML works. Prefer the native\nblocks for normal plans. For architecture/code reviews, use `diagram`\n`data.html` / `data.css` for rich local HTML/SVG diagrams instead of\n`custom-html`. For UI/product work, `custom-html` is never the primary home for a\nrequested mockup, UI state, or visual comparison. If UI fidelity requires\nHTML/CSS, image capture, or real React/CSS, the product fix is canvas support\nfor that artifact type, not moving the mockup into the document.\nWhen `custom-html` is genuinely needed, author it against the sandbox-provided\ntheme tokens (`--wf-paper`, `--wf-card`, `--wf-ink`, `--wf-muted`,\n`--wf-line`, `--wf-radius`, and the matching `--plan-*` aliases). Do not hardcode\nhex/rgb/hsl light palettes such as white cards with dark ink; the same fragment\nmust read in dark mode without a plan-specific patch.\n\n**Before handoff, open the plan and check it.** Fix overlap, excessive\nwhitespace, clipped fragments, misleading inactive controls, poor contrast, and\nunreadable diagrams before asking for approval. Check the top canvas in the\ncurrent Plan theme, especially dark mode: white mockup panels, low-contrast\nmuted text, or invisible controls are defects. If a frame only works in one\ntheme, rewrite the HTML with `--wf-*` tokens and semantic helper classes before\nsurfacing the plan.\n\n<!-- SHARED-CORE:document-quality END -->\n";
12
12
  export declare const EXEMPLAR_REFERENCE_MD = "# Good vs. bad exemplar \u2014 single source of truth\n\nThis file is the canonical worked example of a great plan (and the anti-patterns\nto avoid). Read it alongside the document-quality and canvas references before\nauthoring a plan; it is the bar these plans must clear.\n\n<!-- SHARED-CORE:exemplar START -->\n\n**GOOD.** A UI-first plan for a todo app: a canvas with a `desktop` artboard whose\n`data.html` is a real flex layout \u2014 a sidebar of links (`Inbox 12`, `Today 4`,\n`Done`), a main column with an `<h1>Today</h1>`, accent `.wf-pill`s for the\nfilters, a muted section label `OVERDUE`, and `.wf-card` task rows carrying real\ntitles, due dates, and a primary `button.primary` \u2014 styled only through bare\nelements, helper classes, and `--wf-*` tokens, so the renderer applies the\ncorrect desktop footprint, theme, and one subtle whole-frame wobble. Plain-text\ndesigner notes sit spaced off the frame, pointing only at the controls that need\nexplanation. Below it, a Claude/Codex-grade document: objective and\ndone-criteria, a few `code` blocks (grouped in a vertical `tabs` block when\nmore than one) showing the real shape of the load-bearing files, a `callout`\nwith `tone=\"decision\"` stating the chosen approach with a `columns` block\nweighing the two real options behind it,\nand a validation step \u2014 none of it repeating the canvas. If the task also\nchanges a multi-step completion flow, the same top area includes a Prototype tab\nwhose screens use the same labels and states as the canvas artboards, with\n`data-goto` controls for the sequence. This is the bar.\n\n**GOOD.** A broad product-architecture plan opens with a plain recommendation\nand one concrete app state before the abstraction. The first canvas artboard is\npure product UI that matches the current app shell; nearby notes explain the\nuser-visible delta. A separate diagram below shows the mechanics, such as file\nor data flow. The document then separates the reusable core from app/provider\nadapters and examples, covers contracts, folder or schema shape, sync\nboundaries, roadmap, non-goals, a bottom Open Questions form for unresolved\ndecisions, and a verification section with at least one realistic end-to-end\nsmoke. A reviewer who was not in the chat gets the idea from the top snapshot\nbefore reading the technical plan.\n\n**GOOD.** A `/visual-plan` for a backend architecture review: no top canvas.\nThe document opens with context and a legend, then repeats recommendation cards:\ntitle, confidence/category badges, a monospace grid of real file paths, one\ninline two-dimensional before/after or layered architecture diagram, and terse\nProblem/Solution/Why bullets using the codebase's vocabulary. The diagram uses\nspace to show boundaries, layers, and ownership; it is not a default\nleft-to-right chain. The plan ends with a top recommendation and a bottom\nquestion-form only if the next architecture direction is genuinely open. This is\nbetter than a top canvas because each diagram is local to the claim it supports.\n\n**BAD.** A `data.html` with hard-coded hex colors, a `font-family`, or fixed\npixel width/height; gray placeholder bars \"insinuating\" text on a non-skeleton\nframe; a forced desktop + mobile pair for a popover; floating bordered\nannotation cards hugging the frames; a fresh hand-authored kit-tree `screen`\ninstead of `html`; a multi-step UI flow with only static frames and no prototype\ntab; a mockup escaped into a document `custom-html` block; and a marketing-style\ndocument with a hero heading and value props that just restates what the canvas\nalready shows. Also bad: an architecture-only plan forced into a top canvas of\nlabeled boxes with overlapping text, where the actual code evidence and\nrecommendations live elsewhere; a product wireframe that mixes a real screen\nwith repo names, file-contract arrows, architecture explanations, or a made-up\npermanent inspector; and a plan that describes itself as a revision of a prior\nconversation instead of a standalone proposal. Never produce this.\n\n<!-- SHARED-CORE:exemplar END -->\n";