@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
@@ -28,8 +28,20 @@ export interface RunStuckBannerProps {
28
28
  * observability events (Sentry, PostHog) at the call site.
29
29
  */
30
30
  onStuckStateChange?: (state: RunStuckState) => void;
31
+ /**
32
+ * Automatically abort and retry once when the server reports a run is
33
+ * alive but has stopped making real progress. Manual controls remain visible
34
+ * as the fallback if the automatic recovery cannot clear the run.
35
+ */
36
+ autoRetry?: boolean;
37
+ /**
38
+ * Stable browser-tab/window id used to coordinate automatic retries across
39
+ * multiple mounted chat views for the same thread. A local id is generated
40
+ * when omitted.
41
+ */
42
+ autoRetryOwnerId?: string;
31
43
  /** Extra class on the outer container. */
32
44
  className?: string;
33
45
  }
34
- export declare function RunStuckBanner({ threadId, apiUrl, stuckThresholdMs, onRetry, onStuckStateChange, className, }: RunStuckBannerProps): import("react").JSX.Element | null;
46
+ export declare function RunStuckBanner({ threadId, apiUrl, stuckThresholdMs, onRetry, onStuckStateChange, autoRetry, autoRetryOwnerId, className, }: RunStuckBannerProps): import("react").JSX.Element | null;
35
47
  //# sourceMappingURL=RunStuckBanner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RunStuckBanner.d.ts","sourceRoot":"","sources":["../../src/client/RunStuckBanner.tsx"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AAGtC;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACpD,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,MAAM,EACN,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EAClB,SAAS,GACV,EAAE,mBAAmB,sCA0HrB"}
1
+ {"version":3,"file":"RunStuckBanner.d.ts","sourceRoot":"","sources":["../../src/client/RunStuckBanner.tsx"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AAGtC;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACpD;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2FD,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,MAAM,EACN,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EAClB,SAAiB,EACjB,gBAAgB,EAChB,SAAS,GACV,EAAE,mBAAmB,sCAiMrB"}
@@ -4,10 +4,74 @@ import { useEffect, useRef, useState } from "react";
4
4
  import { trackEvent } from "./analytics.js";
5
5
  import { useRunStuckDetection, useAbortRun, } from "./use-run-stuck-detection.js";
6
6
  import { cn } from "./utils.js";
7
- export function RunStuckBanner({ threadId, apiUrl, stuckThresholdMs, onRetry, onStuckStateChange, className, }) {
7
+ const AUTO_RETRY_CLAIM_TTL_MS = 5 * 60 * 1000;
8
+ const BACKGROUND_WORKER_FRESH_HEARTBEAT_MS = 30_000;
9
+ function createAutoRetryOwnerId() {
10
+ const cryptoApi = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"
11
+ ? crypto
12
+ : null;
13
+ return cryptoApi?.randomUUID() ?? `owner-${Math.random().toString(36)}`;
14
+ }
15
+ function autoRetryClaimKey(threadId, runId) {
16
+ return `agent-native:stuck-auto-retry:${threadId}:${runId}`;
17
+ }
18
+ function isFreshBackgroundWorker(state) {
19
+ return Boolean(state.status === "running" &&
20
+ state.dispatchMode === "background-processing" &&
21
+ state.heartbeatSinceMs != null &&
22
+ state.heartbeatSinceMs >= 0 &&
23
+ state.heartbeatSinceMs < BACKGROUND_WORKER_FRESH_HEARTBEAT_MS);
24
+ }
25
+ function markAutoRetryClaim(key, ownerId) {
26
+ if (typeof window === "undefined")
27
+ return true;
28
+ const now = Date.now();
29
+ try {
30
+ const raw = window.localStorage.getItem(key);
31
+ if (raw) {
32
+ const existing = JSON.parse(raw);
33
+ const expiresAt = typeof existing.expiresAt === "number" ? existing.expiresAt : 0;
34
+ if (expiresAt > now && existing.ownerId !== ownerId)
35
+ return false;
36
+ }
37
+ window.localStorage.setItem(key, JSON.stringify({ ownerId, expiresAt: now + AUTO_RETRY_CLAIM_TTL_MS }));
38
+ const confirmed = JSON.parse(window.localStorage.getItem(key) ?? "{}");
39
+ return confirmed.ownerId === ownerId;
40
+ }
41
+ catch {
42
+ // Private browsing or disabled storage: fall back to in-tab retry. The
43
+ // server abort is idempotent, and manual controls remain available.
44
+ return true;
45
+ }
46
+ }
47
+ async function claimAutoRetryAttempt(threadId, runId, ownerId) {
48
+ if (!threadId)
49
+ return true;
50
+ const key = autoRetryClaimKey(threadId, runId);
51
+ const locks = typeof navigator !== "undefined"
52
+ ? navigator.locks
53
+ : undefined;
54
+ if (locks?.request) {
55
+ try {
56
+ return await locks.request(key, { mode: "exclusive", ifAvailable: true }, (lock) => (lock ? markAutoRetryClaim(key, ownerId) : false));
57
+ }
58
+ catch {
59
+ return markAutoRetryClaim(key, ownerId);
60
+ }
61
+ }
62
+ return markAutoRetryClaim(key, ownerId);
63
+ }
64
+ export function RunStuckBanner({ threadId, apiUrl, stuckThresholdMs, onRetry, onStuckStateChange, autoRetry = false, autoRetryOwnerId, className, }) {
8
65
  const state = useRunStuckDetection({ threadId, stuckThresholdMs, apiUrl });
9
66
  const abortRun = useAbortRun(apiUrl);
10
- const [busy, setBusy] = useState("none");
67
+ const [busy, setBusy] = useState({ type: "none" });
68
+ const autoRetriedRunIdsRef = useRef(new Set());
69
+ const generatedOwnerIdRef = useRef(null);
70
+ if (!generatedOwnerIdRef.current) {
71
+ generatedOwnerIdRef.current = createAutoRetryOwnerId();
72
+ }
73
+ const ownerId = autoRetryOwnerId ?? generatedOwnerIdRef.current;
74
+ const backgroundWorkerStillAlive = isFreshBackgroundWorker(state);
11
75
  const lastReportedRef = useRef({ isStuck: false, runId: null });
12
76
  useEffect(() => {
13
77
  const last = lastReportedRef.current;
@@ -27,40 +91,98 @@ export function RunStuckBanner({ threadId, apiUrl, stuckThresholdMs, onRetry, on
27
91
  });
28
92
  }
29
93
  }, [state, onStuckStateChange, threadId]);
30
- // Reset the busy spinner once the underlying run has flipped away from
31
- // running no need to keep showing a stale "Retrying…" indicator.
94
+ // Reset the busy spinner once the underlying run is no longer the one we
95
+ // acted on. A recovery continuation can start quickly enough that polling
96
+ // never observes an idle state between run ids.
32
97
  useEffect(() => {
33
- if (state.status !== "running") {
34
- setBusy("none");
98
+ setBusy((current) => {
99
+ if (current.type === "none")
100
+ return current;
101
+ if (state.status !== "running")
102
+ return { type: "none" };
103
+ if (state.runId && state.runId !== current.runId)
104
+ return { type: "none" };
105
+ return current;
106
+ });
107
+ }, [state.runId, state.status]);
108
+ useEffect(() => {
109
+ if (!autoRetry ||
110
+ backgroundWorkerStillAlive ||
111
+ !state.isStuck ||
112
+ !state.runId ||
113
+ busy.type !== "none" ||
114
+ autoRetriedRunIdsRef.current.has(state.runId)) {
115
+ return;
35
116
  }
36
- }, [state.status]);
117
+ const runId = state.runId;
118
+ void claimAutoRetryAttempt(threadId, runId, ownerId).then((claimed) => {
119
+ autoRetriedRunIdsRef.current.add(runId);
120
+ if (!claimed)
121
+ return;
122
+ setBusy({ type: "retry", runId });
123
+ trackEvent("agent_chat_stuck_auto_retry", {
124
+ runId,
125
+ threadId: threadId ?? null,
126
+ stuckSinceMs: state.stuckSinceMs ?? null,
127
+ });
128
+ void abortRun(runId, "auto_stuck_retry").then((aborted) => {
129
+ if (aborted) {
130
+ onRetry?.(aborted);
131
+ return;
132
+ }
133
+ setBusy((current) => current.type !== "none" && current.runId === runId
134
+ ? { type: "none" }
135
+ : current);
136
+ });
137
+ });
138
+ }, [
139
+ abortRun,
140
+ autoRetry,
141
+ backgroundWorkerStillAlive,
142
+ busy,
143
+ onRetry,
144
+ ownerId,
145
+ state.isStuck,
146
+ state.runId,
147
+ state.stuckSinceMs,
148
+ threadId,
149
+ ]);
37
150
  if (!state.isStuck || !state.runId)
38
151
  return null;
39
152
  const handleCancel = async () => {
40
- if (!state.runId || busy !== "none")
153
+ if (!state.runId || busy.type !== "none")
41
154
  return;
42
- setBusy("cancel");
155
+ const runId = state.runId;
156
+ setBusy({ type: "cancel", runId });
43
157
  trackEvent("agent_chat_stuck_cancel", {
44
- runId: state.runId,
158
+ runId,
45
159
  threadId: threadId ?? null,
46
160
  stuckSinceMs: state.stuckSinceMs ?? null,
47
161
  });
48
- await abortRun(state.runId, "user_stuck_cancel");
162
+ await abortRun(runId, "user_stuck_cancel");
49
163
  };
50
164
  const handleRetry = async () => {
51
- if (!state.runId || busy !== "none")
165
+ if (!state.runId || busy.type !== "none")
52
166
  return;
53
- setBusy("retry");
167
+ const runId = state.runId;
168
+ setBusy({ type: "retry", runId });
54
169
  trackEvent("agent_chat_stuck_retry", {
55
- runId: state.runId,
170
+ runId,
56
171
  threadId: threadId ?? null,
57
172
  stuckSinceMs: state.stuckSinceMs ?? null,
58
173
  });
59
- const aborted = await abortRun(state.runId, "user_stuck_retry");
174
+ const aborted = await abortRun(runId, "user_stuck_retry");
60
175
  if (aborted)
61
176
  onRetry?.(aborted);
62
177
  };
178
+ const busyType = busy.type;
63
179
  const stuckSeconds = state.stuckSinceMs != null ? Math.floor(state.stuckSinceMs / 1000) : null;
64
- return (_jsxs("div", { role: "status", "aria-live": "polite", className: cn("mx-3 mt-2 flex items-start gap-2.5 rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2.5 text-xs text-foreground", className), children: [_jsx(IconAlertTriangle, { size: 16, className: "mt-0.5 shrink-0 text-amber-500", "aria-hidden": "true" }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [_jsxs("div", { className: "leading-snug", children: [_jsx("span", { className: "font-medium", children: "This chat looks stuck." }), " ", _jsxs("span", { className: "text-muted-foreground", children: ["No progress", stuckSeconds != null ? ` for ${stuckSeconds}s` : "", ". The agent may have hit a server timeout or lost its connection."] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("button", { type: "button", onClick: handleRetry, disabled: busy !== "none", className: "inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md bg-foreground px-2.5 text-[11px] font-medium text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:opacity-60", children: [busy === "retry" ? (_jsx(IconLoader2, { size: 12, className: "animate-spin", "aria-hidden": "true" })) : null, "Retry"] }), _jsxs("button", { type: "button", onClick: handleCancel, disabled: busy !== "none", className: "inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[11px] font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-60", children: [busy === "cancel" ? (_jsx(IconLoader2, { size: 12, className: "animate-spin", "aria-hidden": "true" })) : null, "Cancel"] })] })] })] }));
180
+ return (_jsxs("div", { role: "status", "aria-live": "polite", className: cn("mx-3 mt-2 flex items-start gap-2.5 rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2.5 text-xs text-foreground", className), children: [_jsx(IconAlertTriangle, { size: 16, className: "mt-0.5 shrink-0 text-amber-500", "aria-hidden": "true" }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [_jsxs("div", { className: "leading-snug", children: [_jsx("span", { className: "font-medium", children: backgroundWorkerStillAlive
181
+ ? "The agent is still working."
182
+ : "This chat looks stuck." }), " ", _jsxs("span", { className: "text-muted-foreground", children: ["No progress", stuckSeconds != null ? ` for ${stuckSeconds}s` : "", ".", " ", backgroundWorkerStillAlive
183
+ ? "The background worker is still alive; large updates can take a few minutes."
184
+ : "The agent may have hit a server timeout or lost its connection.", autoRetry && busyType === "retry"
185
+ ? " Retrying automatically now."
186
+ : ""] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("button", { type: "button", onClick: handleRetry, disabled: busyType !== "none", className: "inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md bg-foreground px-2.5 text-[11px] font-medium text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:opacity-60", children: [busyType === "retry" ? (_jsx(IconLoader2, { size: 12, className: "animate-spin", "aria-hidden": "true" })) : null, "Retry"] }), _jsxs("button", { type: "button", onClick: handleCancel, disabled: busyType !== "none", className: "inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[11px] font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-60", children: [busyType === "cancel" ? (_jsx(IconLoader2, { size: 12, className: "animate-spin", "aria-hidden": "true" })) : null, "Cancel"] })] })] })] }));
65
187
  }
66
188
  //# sourceMappingURL=RunStuckBanner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RunStuckBanner.js","sourceRoot":"","sources":["../../src/client/RunStuckBanner.tsx"],"names":[],"mappings":"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","sourcesContent":["import { IconAlertTriangle, IconLoader2 } from \"@tabler/icons-react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { trackEvent } from \"./analytics.js\";\nimport {\n useRunStuckDetection,\n useAbortRun,\n type RunStuckState,\n} from \"./use-run-stuck-detection.js\";\nimport { cn } from \"./utils.js\";\n\n/**\n * Surface a user-visible affordance when a chat run hasn't emitted any\n * events for an unusually long time. The adapter's silent reconnect logic\n * keeps trying in the background; this banner is the fallback when those\n * attempts haven't restored progress and the user is staring at a frozen\n * spinner.\n */\nexport interface RunStuckBannerProps {\n /** The thread to monitor. Pass null/undefined to disable. */\n threadId: string | null | undefined;\n /** API base path. Default `/_agent-native/agent-chat`. */\n apiUrl?: string;\n /**\n * Threshold above which an in-flight run is considered stuck.\n * Defaults to 90s (after the adapter's 75s no-progress reconnect\n * has had a chance to recover).\n */\n stuckThresholdMs?: number;\n /**\n * Called when the user clicks Retry. Implementations should re-prompt\n * the agent (typically via `chatHandle.sendMessage(...)`) — the banner\n * itself only handles aborting the prior run.\n */\n onRetry?: (runId: string) => void;\n /**\n * Called whenever the stuck state transitions. Useful for surfacing\n * observability events (Sentry, PostHog) at the call site.\n */\n onStuckStateChange?: (state: RunStuckState) => void;\n /** Extra class on the outer container. */\n className?: string;\n}\n\nexport function RunStuckBanner({\n threadId,\n apiUrl,\n stuckThresholdMs,\n onRetry,\n onStuckStateChange,\n className,\n}: RunStuckBannerProps) {\n const state = useRunStuckDetection({ threadId, stuckThresholdMs, apiUrl });\n const abortRun = useAbortRun(apiUrl);\n const [busy, setBusy] = useState<\"none\" | \"cancel\" | \"retry\">(\"none\");\n\n const lastReportedRef = useRef<{\n isStuck: boolean;\n runId: string | null;\n }>({ isStuck: false, runId: null });\n useEffect(() => {\n const last = lastReportedRef.current;\n if (last.isStuck === state.isStuck && last.runId === state.runId) return;\n lastReportedRef.current = { isStuck: state.isStuck, runId: state.runId };\n onStuckStateChange?.(state);\n if (state.isStuck && state.runId) {\n trackEvent(\"agent_chat_stuck_detected\", {\n runId: state.runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n stuckSinceSec:\n state.stuckSinceMs != null\n ? Math.floor(state.stuckSinceMs / 1000)\n : null,\n runStatus: state.status,\n });\n }\n }, [state, onStuckStateChange, threadId]);\n\n // Reset the busy spinner once the underlying run has flipped away from\n // running — no need to keep showing a stale \"Retrying…\" indicator.\n useEffect(() => {\n if (state.status !== \"running\") {\n setBusy(\"none\");\n }\n }, [state.status]);\n\n if (!state.isStuck || !state.runId) return null;\n\n const handleCancel = async () => {\n if (!state.runId || busy !== \"none\") return;\n setBusy(\"cancel\");\n trackEvent(\"agent_chat_stuck_cancel\", {\n runId: state.runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n await abortRun(state.runId, \"user_stuck_cancel\");\n };\n\n const handleRetry = async () => {\n if (!state.runId || busy !== \"none\") return;\n setBusy(\"retry\");\n trackEvent(\"agent_chat_stuck_retry\", {\n runId: state.runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n const aborted = await abortRun(state.runId, \"user_stuck_retry\");\n if (aborted) onRetry?.(aborted);\n };\n\n const stuckSeconds =\n state.stuckSinceMs != null ? Math.floor(state.stuckSinceMs / 1000) : null;\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"mx-3 mt-2 flex items-start gap-2.5 rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2.5 text-xs text-foreground\",\n className,\n )}\n >\n <IconAlertTriangle\n size={16}\n className=\"mt-0.5 shrink-0 text-amber-500\"\n aria-hidden=\"true\"\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <div className=\"leading-snug\">\n <span className=\"font-medium\">This chat looks stuck.</span>{\" \"}\n <span className=\"text-muted-foreground\">\n No progress\n {stuckSeconds != null ? ` for ${stuckSeconds}s` : \"\"}. The agent may\n have hit a server timeout or lost its connection.\n </span>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleRetry}\n disabled={busy !== \"none\"}\n className=\"inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md bg-foreground px-2.5 text-[11px] font-medium text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {busy === \"retry\" ? (\n <IconLoader2\n size={12}\n className=\"animate-spin\"\n aria-hidden=\"true\"\n />\n ) : null}\n Retry\n </button>\n <button\n type=\"button\"\n onClick={handleCancel}\n disabled={busy !== \"none\"}\n className=\"inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[11px] font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {busy === \"cancel\" ? (\n <IconLoader2\n size={12}\n className=\"animate-spin\"\n aria-hidden=\"true\"\n />\n ) : null}\n Cancel\n </button>\n </div>\n </div>\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"RunStuckBanner.js","sourceRoot":"","sources":["../../src/client/RunStuckBanner.tsx"],"names":[],"mappings":"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","sourcesContent":["import { IconAlertTriangle, IconLoader2 } from \"@tabler/icons-react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { trackEvent } from \"./analytics.js\";\nimport {\n useRunStuckDetection,\n useAbortRun,\n type RunStuckState,\n} from \"./use-run-stuck-detection.js\";\nimport { cn } from \"./utils.js\";\n\n/**\n * Surface a user-visible affordance when a chat run hasn't emitted any\n * events for an unusually long time. The adapter's silent reconnect logic\n * keeps trying in the background; this banner is the fallback when those\n * attempts haven't restored progress and the user is staring at a frozen\n * spinner.\n */\nexport interface RunStuckBannerProps {\n /** The thread to monitor. Pass null/undefined to disable. */\n threadId: string | null | undefined;\n /** API base path. Default `/_agent-native/agent-chat`. */\n apiUrl?: string;\n /**\n * Threshold above which an in-flight run is considered stuck.\n * Defaults to 90s (after the adapter's 75s no-progress reconnect\n * has had a chance to recover).\n */\n stuckThresholdMs?: number;\n /**\n * Called when the user clicks Retry. Implementations should re-prompt\n * the agent (typically via `chatHandle.sendMessage(...)`) — the banner\n * itself only handles aborting the prior run.\n */\n onRetry?: (runId: string) => void;\n /**\n * Called whenever the stuck state transitions. Useful for surfacing\n * observability events (Sentry, PostHog) at the call site.\n */\n onStuckStateChange?: (state: RunStuckState) => void;\n /**\n * Automatically abort and retry once when the server reports a run is\n * alive but has stopped making real progress. Manual controls remain visible\n * as the fallback if the automatic recovery cannot clear the run.\n */\n autoRetry?: boolean;\n /**\n * Stable browser-tab/window id used to coordinate automatic retries across\n * multiple mounted chat views for the same thread. A local id is generated\n * when omitted.\n */\n autoRetryOwnerId?: string;\n /** Extra class on the outer container. */\n className?: string;\n}\n\nconst AUTO_RETRY_CLAIM_TTL_MS = 5 * 60 * 1000;\nconst BACKGROUND_WORKER_FRESH_HEARTBEAT_MS = 30_000;\n\ntype BusyState = { type: \"none\" } | { type: \"cancel\" | \"retry\"; runId: string };\n\ntype MaybeLockManager = {\n request<T>(\n name: string,\n options: { mode?: \"exclusive\" | \"shared\"; ifAvailable?: boolean },\n callback: (lock: unknown) => T | Promise<T>,\n ): Promise<T>;\n};\n\nfunction createAutoRetryOwnerId() {\n const cryptoApi =\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? crypto\n : null;\n return cryptoApi?.randomUUID() ?? `owner-${Math.random().toString(36)}`;\n}\n\nfunction autoRetryClaimKey(threadId: string, runId: string) {\n return `agent-native:stuck-auto-retry:${threadId}:${runId}`;\n}\n\nfunction isFreshBackgroundWorker(state: RunStuckState): boolean {\n return Boolean(\n state.status === \"running\" &&\n state.dispatchMode === \"background-processing\" &&\n state.heartbeatSinceMs != null &&\n state.heartbeatSinceMs >= 0 &&\n state.heartbeatSinceMs < BACKGROUND_WORKER_FRESH_HEARTBEAT_MS,\n );\n}\n\nfunction markAutoRetryClaim(key: string, ownerId: string) {\n if (typeof window === \"undefined\") return true;\n const now = Date.now();\n try {\n const raw = window.localStorage.getItem(key);\n if (raw) {\n const existing = JSON.parse(raw) as {\n ownerId?: unknown;\n expiresAt?: unknown;\n };\n const expiresAt =\n typeof existing.expiresAt === \"number\" ? existing.expiresAt : 0;\n if (expiresAt > now && existing.ownerId !== ownerId) return false;\n }\n window.localStorage.setItem(\n key,\n JSON.stringify({ ownerId, expiresAt: now + AUTO_RETRY_CLAIM_TTL_MS }),\n );\n const confirmed = JSON.parse(window.localStorage.getItem(key) ?? \"{}\") as {\n ownerId?: unknown;\n };\n return confirmed.ownerId === ownerId;\n } catch {\n // Private browsing or disabled storage: fall back to in-tab retry. The\n // server abort is idempotent, and manual controls remain available.\n return true;\n }\n}\n\nasync function claimAutoRetryAttempt(\n threadId: string | null | undefined,\n runId: string,\n ownerId: string,\n) {\n if (!threadId) return true;\n const key = autoRetryClaimKey(threadId, runId);\n const locks =\n typeof navigator !== \"undefined\"\n ? (navigator as Navigator & { locks?: MaybeLockManager }).locks\n : undefined;\n if (locks?.request) {\n try {\n return await locks.request(\n key,\n { mode: \"exclusive\", ifAvailable: true },\n (lock) => (lock ? markAutoRetryClaim(key, ownerId) : false),\n );\n } catch {\n return markAutoRetryClaim(key, ownerId);\n }\n }\n return markAutoRetryClaim(key, ownerId);\n}\n\nexport function RunStuckBanner({\n threadId,\n apiUrl,\n stuckThresholdMs,\n onRetry,\n onStuckStateChange,\n autoRetry = false,\n autoRetryOwnerId,\n className,\n}: RunStuckBannerProps) {\n const state = useRunStuckDetection({ threadId, stuckThresholdMs, apiUrl });\n const abortRun = useAbortRun(apiUrl);\n const [busy, setBusy] = useState<BusyState>({ type: \"none\" });\n const autoRetriedRunIdsRef = useRef<Set<string>>(new Set());\n const generatedOwnerIdRef = useRef<string | null>(null);\n if (!generatedOwnerIdRef.current) {\n generatedOwnerIdRef.current = createAutoRetryOwnerId();\n }\n const ownerId = autoRetryOwnerId ?? generatedOwnerIdRef.current;\n const backgroundWorkerStillAlive = isFreshBackgroundWorker(state);\n\n const lastReportedRef = useRef<{\n isStuck: boolean;\n runId: string | null;\n }>({ isStuck: false, runId: null });\n useEffect(() => {\n const last = lastReportedRef.current;\n if (last.isStuck === state.isStuck && last.runId === state.runId) return;\n lastReportedRef.current = { isStuck: state.isStuck, runId: state.runId };\n onStuckStateChange?.(state);\n if (state.isStuck && state.runId) {\n trackEvent(\"agent_chat_stuck_detected\", {\n runId: state.runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n stuckSinceSec:\n state.stuckSinceMs != null\n ? Math.floor(state.stuckSinceMs / 1000)\n : null,\n runStatus: state.status,\n });\n }\n }, [state, onStuckStateChange, threadId]);\n\n // Reset the busy spinner once the underlying run is no longer the one we\n // acted on. A recovery continuation can start quickly enough that polling\n // never observes an idle state between run ids.\n useEffect(() => {\n setBusy((current) => {\n if (current.type === \"none\") return current;\n if (state.status !== \"running\") return { type: \"none\" };\n if (state.runId && state.runId !== current.runId) return { type: \"none\" };\n return current;\n });\n }, [state.runId, state.status]);\n\n useEffect(() => {\n if (\n !autoRetry ||\n backgroundWorkerStillAlive ||\n !state.isStuck ||\n !state.runId ||\n busy.type !== \"none\" ||\n autoRetriedRunIdsRef.current.has(state.runId)\n ) {\n return;\n }\n\n const runId = state.runId;\n void claimAutoRetryAttempt(threadId, runId, ownerId).then((claimed) => {\n autoRetriedRunIdsRef.current.add(runId);\n if (!claimed) return;\n setBusy({ type: \"retry\", runId });\n trackEvent(\"agent_chat_stuck_auto_retry\", {\n runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n void abortRun(runId, \"auto_stuck_retry\").then((aborted) => {\n if (aborted) {\n onRetry?.(aborted);\n return;\n }\n setBusy((current) =>\n current.type !== \"none\" && current.runId === runId\n ? { type: \"none\" }\n : current,\n );\n });\n });\n }, [\n abortRun,\n autoRetry,\n backgroundWorkerStillAlive,\n busy,\n onRetry,\n ownerId,\n state.isStuck,\n state.runId,\n state.stuckSinceMs,\n threadId,\n ]);\n\n if (!state.isStuck || !state.runId) return null;\n\n const handleCancel = async () => {\n if (!state.runId || busy.type !== \"none\") return;\n const runId = state.runId;\n setBusy({ type: \"cancel\", runId });\n trackEvent(\"agent_chat_stuck_cancel\", {\n runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n await abortRun(runId, \"user_stuck_cancel\");\n };\n\n const handleRetry = async () => {\n if (!state.runId || busy.type !== \"none\") return;\n const runId = state.runId;\n setBusy({ type: \"retry\", runId });\n trackEvent(\"agent_chat_stuck_retry\", {\n runId,\n threadId: threadId ?? null,\n stuckSinceMs: state.stuckSinceMs ?? null,\n });\n const aborted = await abortRun(runId, \"user_stuck_retry\");\n if (aborted) onRetry?.(aborted);\n };\n\n const busyType = busy.type;\n\n const stuckSeconds =\n state.stuckSinceMs != null ? Math.floor(state.stuckSinceMs / 1000) : null;\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"mx-3 mt-2 flex items-start gap-2.5 rounded-md border border-amber-500/40 bg-amber-500/10 px-3 py-2.5 text-xs text-foreground\",\n className,\n )}\n >\n <IconAlertTriangle\n size={16}\n className=\"mt-0.5 shrink-0 text-amber-500\"\n aria-hidden=\"true\"\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <div className=\"leading-snug\">\n <span className=\"font-medium\">\n {backgroundWorkerStillAlive\n ? \"The agent is still working.\"\n : \"This chat looks stuck.\"}\n </span>{\" \"}\n <span className=\"text-muted-foreground\">\n No progress\n {stuckSeconds != null ? ` for ${stuckSeconds}s` : \"\"}.{\" \"}\n {backgroundWorkerStillAlive\n ? \"The background worker is still alive; large updates can take a few minutes.\"\n : \"The agent may have hit a server timeout or lost its connection.\"}\n {autoRetry && busyType === \"retry\"\n ? \" Retrying automatically now.\"\n : \"\"}\n </span>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleRetry}\n disabled={busyType !== \"none\"}\n className=\"inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md bg-foreground px-2.5 text-[11px] font-medium text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {busyType === \"retry\" ? (\n <IconLoader2\n size={12}\n className=\"animate-spin\"\n aria-hidden=\"true\"\n />\n ) : null}\n Retry\n </button>\n <button\n type=\"button\"\n onClick={handleCancel}\n disabled={busyType !== \"none\"}\n className=\"inline-flex h-7 cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[11px] font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {busyType === \"cancel\" ? (\n <IconLoader2\n size={12}\n className=\"animate-spin\"\n aria-hidden=\"true\"\n />\n ) : null}\n Cancel\n </button>\n </div>\n </div>\n </div>\n );\n}\n"]}
@@ -9,10 +9,10 @@ import type { WireframeElName, WireframeNode, WireframeTone } from "./wireframe.
9
9
  * DECOUPLING: the only behavioral change from the plan copy is theme detection —
10
10
  * core blocks read `document.documentElement.classList.contains("dark")` (the
11
11
  * MermaidBlock precedent) instead of importing `next-themes`. Everything else
12
- * (the `.plan-wf` / `[data-rough]` class contract the rough overlay measures,
13
- * the `--wf-*` / `--ink` / `--paper` token names every primitive reads) is
14
- * preserved exactly, so the kit looks identical in plan and renders correctly in
15
- * any app once the matching tokens exist in `core/styles/blocks.css`.
12
+ * (the `.plan-wf` / `.wf-*` / `[data-rough]` class contract the rough overlay
13
+ * measures, the `--wf-*` / `--ink` / `--paper` token names every primitive
14
+ * reads) is preserved exactly, so the kit looks identical in plan and renders
15
+ * correctly in any app once the matching tokens exist in `core/styles/blocks.css`.
16
16
  */
17
17
  export type WireframeStyle = "sketchy" | "clean";
18
18
  export declare function setWireframeStyle(style: WireframeStyle): void;
@@ -240,8 +240,8 @@ export declare function renderNodes(nodes: WireframeNode[]): ReactNode;
240
240
  /** Whether an `el` name has a registered renderer. */
241
241
  export declare function hasRenderer(el: string): el is WireframeElName;
242
242
  export { REGISTRY as NODE_REGISTRY, V as WFV, toneColors, toneInk, fontWeight };
243
- /** The default selector used for HTML mockups: controls plus explicit opt-ins. */
244
- export declare const HTML_ROUGH_SELECTOR = "[data-rough],button,input,textarea,select,hr";
243
+ /** The default selector used for HTML mockups: standard wireframe primitives plus explicit opt-ins. */
244
+ export declare const HTML_ROUGH_SELECTOR = "[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:']";
245
245
  /** Map the 0–100 sketch slider to a rough.js roughness (calm + legible). */
246
246
  export declare function sketchRoughness(sketch: number): number;
247
247
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"wireframe-kit.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/wireframe-kit.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,aAAa,EACd,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;GAaG;AAMH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,OAAO,CAAC;AAkBjD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAS7D;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAqBD,wBAAgB,iBAAiB,IAAI,cAAc,CAMlD;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,IAAI,OAAO,CAYnC;AAMD;;;GAGG;AACH,eAAO,MAAM,gBAAgB;eAChB,OAAO;aACT,MAAM;YACP,OAAO,GAAG,MAAM;YAChB,SAAS,GAAG,OAAO;EACvB,CAAC;AAEP,QAAA,MAAM,CAAC;aACL,GAAG,EAAE,YAAY;aACjB,IAAI,EAAE,iBAAiB;aACvB,IAAI,EAAE,aAAa;aACnB,KAAK,EAAE,cAAc;aACrB,IAAI,EAAE,aAAa;aACnB,MAAM,EAAE,eAAe;aACvB,UAAU,EAAE,oBAAoB;aAChC,IAAI,EAAE,aAAa;aACnB,QAAQ,EAAE,kBAAkB;aAC5B,EAAE,EAAE,WAAW;aACf,MAAM,EAAE,gBAAgB;aACxB,MAAM,EAAE,eAAe;aACvB,MAAM,EAAE,eAAe;aACvB,GAAG,EAAE,YAAY;aACjB,GAAG,EAAE,YAAY;aACjB,EAAE,EAAE,WAAW;aACf,IAAI,EAAE,kBAAkB;aACxB,MAAM,EAAE,oBAAoB;CACpB,CAAC;AAEX,KAAK,UAAU,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,iBAAS,UAAU,CAAC,IAAI,GAAE,aAAyB,GAAG,UAAU,CAa/D;AAED,iBAAS,OAAO,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAE7C;AAED,iBAAS,UAAU,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAIjE;AAED,wBAAgB,MAAM,CAAC,EACrB,QAAQ,EACR,GAAO,EACP,MAAM,EACN,OAAO,EACP,KAAK,EACL,QAAgB,EAChB,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IAC1C,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAqCA;AAED,wBAAgB,IAAI,CAAC,EACnB,QAAQ,EACR,IAAI,EACJ,MAAY,EACZ,KAAa,EACb,MAAc,EACd,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAgBA;AAED,wBAAgB,GAAG,CAAC,EAClB,CAAM,EACN,CAAC,EACD,KAAc,EACd,CAAK,EACL,KAAU,GACX,EAAE;IACD,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAaA;AAED,wBAAgB,KAAK,CAAC,EACpB,CAAK,EACL,GAAO,EACP,MAAM,EACN,KAAc,EACd,KAAU,GACX,EAAE;IACD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAWA;AAED,wBAAgB,GAAG,CAAC,EAClB,QAAQ,EACR,GAAW,EACX,IAAa,EACb,MAAc,EACd,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAkBA;AAED,wBAAgB,KAAK,CAAC,EACpB,IAAY,EACZ,KAAgB,EAChB,IAAS,GACV,EAAE;IACD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,+BAkCA;AAED,wBAAgB,IAAI,CAAC,EACnB,QAAQ,EACR,IAAgB,EAChB,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BA0BA;AAED,wBAAgB,IAAI,CAAC,EAAE,KAAS,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,+BAsB5E;AAED,wBAAgB,GAAG,CAAC,EAClB,QAAQ,EACR,KAAa,EACb,IAAY,EACZ,IAAW,EACX,IAAgB,EAChB,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAkCA;AAED,wBAAgB,IAAI,CAAC,EACnB,QAAQ,EACR,MAAc,EACd,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAyBA;AAED,wBAAgB,KAAK,CAAC,EACpB,KAAK,EACL,KAAK,EACL,WAAW,EACX,CAAC,EACD,IAAY,EACZ,KAAK,EACL,KAAU,GACX,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAmCA;AAED,wBAAgB,SAAS,gCAqBxB;AAED,wBAAgB,GAAG,CAAC,EAAE,IAAU,EAAE,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,+BA6BpD;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAc,EACd,QAAQ,GACT,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,+BAiDA;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,KAAK,EACL,IAAc,GACf,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB,+BA0BA;AAED,wBAAgB,MAAM,CAAC,EAAE,IAAS,EAAE,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,+BAetD;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAS,EACT,MAAc,GACf,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,+BA0BA;AAED,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,KAAK,EACL,MAAc,EACd,GAAW,EACX,IAAe,GAChB,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB,+BA0CA;AAED,wBAAgB,OAAO,CAAC,EACtB,QAAQ,EACR,KAAW,EACX,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAwBA;AAED,wBAAgB,IAAI,CAAC,EACnB,QAAQ,EACR,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAkBA;AAED,wBAAgB,GAAG,CAAC,EAClB,QAAQ,EACR,IAAY,EACZ,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAkBA;AAED,wBAAgB,GAAG,CAAC,EAClB,QAAQ,EACR,IAAY,EACZ,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAgBA;AAED,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,IAAI,EACJ,GAAG,EACH,OAAmB,EACnB,IAAI,EACJ,IAAY,GACb,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,+BAkDA;AAED,wBAAgB,IAAI,CAAC,EACnB,QAAQ,EACR,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAiBA;AAED,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,KAAK,EACL,IAAc,EACd,KAAW,EACX,QAAQ,GACT,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,+BAqCA;AAED,wBAAgB,OAAO,CAAC,EACtB,QAAQ,EACR,KAAU,GACX,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,+BAsBA;AAED,wBAAgB,IAAI,CAAC,EACnB,KAAU,GACX,EAAE;IACD,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACpD,+BAUA;AAED,wBAAgB,EAAE,CAAC,EAAE,IAAS,EAAE,EAAE;IAAE,IAAI,CAAC,EAAE,KAAK,CAAC;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,+BAyB3E;AAED,wBAAgB,SAAS,CAAC,EACxB,WAAsB,GACvB,EAAE;IACD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,+BAmBA;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAU,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,aAAa,CAAA;CAAE,+BAYhE;AAED,wBAAgB,KAAK,CAAC,EACpB,IAAI,EACJ,MAAc,EACd,IAA4B,EAC5B,KAAa,GACd,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,+BAMA;AAED,wBAAgB,IAAI,CAAC,EACnB,KAAK,EACL,KAAK,EACL,MAAM,EACN,MAAc,GACf,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,+BAMA;AAMD,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,KAAK,SAAS,CAAC;AAE5E,QAAA,MAAM,QAAQ,EAAE,MAAM,CAAC,eAAe,EAAE,YAAY,CAqHnD,CAAC;AAkBF,qEAAqE;AACrE,wBAAgB,UAAU,CACxB,IAAI,EAAE,aAAa,EACnB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GACpB,SAAS,CAQX;AAED,gCAAgC;AAChC,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,SAAS,CAE7D;AAOD,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,eAAe,CAE7D;AAED,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,CAAC,IAAI,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AAUhF,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,iDACgB,CAAC;AAajD,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtD;AAqMD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,MAAW,EACX,OAAc,EACd,SAAgB,EAChB,WAAgB,EAChB,QAAyB,GAC1B,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,sCAyGA"}
1
+ {"version":3,"file":"wireframe-kit.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/wireframe-kit.tsx"],"names":[],"mappings":"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"}
@@ -134,7 +134,7 @@ export function Screen({ children, pad = 0, sketch, density, theme, skeleton = f
134
134
  // clipping. The frame shell (`ArtboardFrame`) owns the height policy; a
135
135
  // caller can still override via `style.height` for a fixed canvas.
136
136
  minHeight: "100%",
137
- background: V.paper,
137
+ background: "transparent",
138
138
  color: V.ink,
139
139
  fontFamily: V.hand,
140
140
  fontSize: V.fs,
@@ -658,8 +658,8 @@ export { REGISTRY as NODE_REGISTRY, V as WFV, toneColors, toneInk, fontWeight };
658
658
  /* Rough overlay (ported from kit/rough.tsx) */
659
659
  /* ========================================================================== */
660
660
  const gen = rough.generator();
661
- /** The default selector used for HTML mockups: controls plus explicit opt-ins. */
662
- export const HTML_ROUGH_SELECTOR = "[data-rough],button,input,textarea,select,hr";
661
+ /** The default selector used for HTML mockups: standard wireframe primitives plus explicit opt-ins. */
662
+ export const HTML_ROUGH_SELECTOR = "[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:']";
663
663
  /** Stable per-element seed so a frame doesn't re-wobble on every measure. */
664
664
  function seedFrom(...parts) {
665
665
  const value = parts.join(":");
@@ -744,6 +744,47 @@ function elementStroke(node, fallback) {
744
744
  }
745
745
  return fallback;
746
746
  }
747
+ function visibleBorderSides(node) {
748
+ const cs = getComputedStyle(node);
749
+ const sides = [];
750
+ for (const [side, widthProp, colorProp] of [
751
+ ["top", "borderTopWidth", "borderTopColor"],
752
+ ["right", "borderRightWidth", "borderRightColor"],
753
+ ["bottom", "borderBottomWidth", "borderBottomColor"],
754
+ ["left", "borderLeftWidth", "borderLeftColor"],
755
+ ]) {
756
+ const width = parseFloat(cs[widthProp]);
757
+ const color = cs[colorProp];
758
+ if (width > 0 &&
759
+ color &&
760
+ color !== "rgba(0, 0, 0, 0)" &&
761
+ color !== "transparent") {
762
+ sides.push(side);
763
+ }
764
+ }
765
+ return sides;
766
+ }
767
+ function inferRoughKind(node) {
768
+ const explicit = node.getAttribute("data-rough");
769
+ if (explicit)
770
+ return explicit;
771
+ if (node.tagName === "HR")
772
+ return "line:middle";
773
+ const sides = visibleBorderSides(node);
774
+ if (sides.length !== 1)
775
+ return "rect";
776
+ switch (sides[0]) {
777
+ case "top":
778
+ return "line:top";
779
+ case "right":
780
+ return "line:right";
781
+ case "bottom":
782
+ return "line:bottom";
783
+ case "left":
784
+ return "line:left";
785
+ }
786
+ return "rect";
787
+ }
747
788
  function build(scope, opts) {
748
789
  const base = scope.getBoundingClientRect();
749
790
  const layoutW = scope.offsetWidth;
@@ -796,7 +837,7 @@ function build(scope, opts) {
796
837
  const h = r.height / zoom;
797
838
  if (w < 2 || h < 2)
798
839
  return;
799
- const kind = node.getAttribute("data-rough") || "rect";
840
+ const kind = inferRoughKind(node);
800
841
  const rawStroke = elementStroke(node, sketch);
801
842
  const stroke = sameColor(rawStroke, ink) || (line !== "" && sameColor(rawStroke, line))
802
843
  ? sketch
@@ -808,13 +849,19 @@ function build(scope, opts) {
808
849
  if (kind === "ellipse") {
809
850
  drawable = gen.ellipse(x + w / 2, y + h / 2, w, h, o);
810
851
  }
852
+ else if (kind === "line:left") {
853
+ drawable = gen.line(x, y, x, y + h, o);
854
+ }
811
855
  else if (kind === "line:right") {
812
856
  drawable = gen.line(x + w, y, x + w, y + h, o);
813
857
  }
814
858
  else if (kind === "line:bottom") {
815
859
  drawable = gen.line(x, y + h, x + w, y + h, o);
816
860
  }
817
- else if (kind === "line:top" || node.tagName === "HR") {
861
+ else if (kind === "line:top") {
862
+ drawable = gen.line(x, y, x + w, y, o);
863
+ }
864
+ else if (kind === "line:middle") {
818
865
  drawable = gen.line(x, y + h / 2, x + w, y + h / 2, o);
819
866
  }
820
867
  else {