reflex-agent 0.3.0 → 0.3.1

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 (148) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +101 -101
  3. package/.next/app-path-routes-manifest.json +9 -9
  4. package/.next/build-manifest.json +5 -5
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/react-loadable-manifest.json +1 -1
  7. package/.next/server/app/_not-found/page.js +1 -1
  8. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  9. package/.next/server/app/agents/[agentId]/page.js +2 -2
  10. package/.next/server/app/agents/[agentId]/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/agents/[agentId]/respond/route.js +1 -1
  12. package/.next/server/app/api/agents/[agentId]/respond/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/images/[rootId]/[file]/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/oauth/callback/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/oauth/start/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/roots/[id]/attachments/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/roots/[id]/chat/[topicId]/send/route.js +1 -1
  18. package/.next/server/app/api/roots/[id]/chat/[topicId]/send/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/roots/[id]/chat/[topicId]/stop/route.js +1 -1
  20. package/.next/server/app/api/roots/[id]/chat/[topicId]/stop/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/roots/[id]/chat/[topicId]/stream/route.js +1 -1
  22. package/.next/server/app/api/roots/[id]/chat/[topicId]/stream/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/roots/[id]/dashboard/route.js +1 -1
  24. package/.next/server/app/api/roots/[id]/dashboard/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/roots/[id]/suggestions/route.js +1 -1
  26. package/.next/server/app/api/roots/[id]/suggestions/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/utilities/[scope]/[id]/bundle.js/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/utilities/[scope]/[id]/host/route.js +1 -1
  29. package/.next/server/app/api/utilities/[scope]/[id]/host/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/utilities/[scope]/[id]/host-api.mjs/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/utilities/[scope]/[id]/host-ui.mjs/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/utilities/[scope]/[id]/iframe/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/utilities/[scope]/[id]/style.css/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/audit/page.js +1 -1
  35. package/.next/server/app/audit/page.js.nft.json +1 -1
  36. package/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  37. package/.next/server/app/onboarding/page.js +3 -3
  38. package/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
  39. package/.next/server/app/page.js +2 -2
  40. package/.next/server/app/page.js.nft.json +1 -1
  41. package/.next/server/app/page_client-reference-manifest.js +1 -1
  42. package/.next/server/app/roots/[id]/chat/[topicId]/page.js +2 -2
  43. package/.next/server/app/roots/[id]/chat/[topicId]/page.js.nft.json +1 -1
  44. package/.next/server/app/roots/[id]/chat/[topicId]/page_client-reference-manifest.js +1 -1
  45. package/.next/server/app/roots/[id]/kb/[...slug]/page.js +2 -2
  46. package/.next/server/app/roots/[id]/kb/[...slug]/page.js.nft.json +1 -1
  47. package/.next/server/app/roots/[id]/kb/[...slug]/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/roots/[id]/page.js +3 -3
  49. package/.next/server/app/roots/[id]/page.js.nft.json +1 -1
  50. package/.next/server/app/roots/[id]/page_client-reference-manifest.js +1 -1
  51. package/.next/server/app/roots/[id]/workflows/[wfId]/page.js +2 -2
  52. package/.next/server/app/roots/[id]/workflows/[wfId]/page_client-reference-manifest.js +1 -1
  53. package/.next/server/app/roots/[id]/workflows/page.js +1 -1
  54. package/.next/server/app/roots/[id]/workflows/page.js.nft.json +1 -1
  55. package/.next/server/app/roots/[id]/workflows/page_client-reference-manifest.js +1 -1
  56. package/.next/server/app/roots/new/page.js +4 -4
  57. package/.next/server/app/roots/new/page_client-reference-manifest.js +1 -1
  58. package/.next/server/app/settings/page.js +5 -5
  59. package/.next/server/app/settings/page.js.nft.json +1 -1
  60. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  61. package/.next/server/app/share/[id]/file/page.js +2 -2
  62. package/.next/server/app/share/[id]/file/page_client-reference-manifest.js +1 -1
  63. package/.next/server/app/share/[id]/page.js +2 -2
  64. package/.next/server/app/share/[id]/page.js.nft.json +1 -1
  65. package/.next/server/app/share/[id]/page_client-reference-manifest.js +1 -1
  66. package/.next/server/app/utilities/[scope]/[id]/page.js +2 -2
  67. package/.next/server/app/utilities/[scope]/[id]/page.js.nft.json +1 -1
  68. package/.next/server/app/utilities/[scope]/[id]/page_client-reference-manifest.js +1 -1
  69. package/.next/server/app/utilities/page.js +2 -2
  70. package/.next/server/app/utilities/page_client-reference-manifest.js +1 -1
  71. package/.next/server/app-paths-manifest.json +9 -9
  72. package/.next/server/chunks/285.js +3 -3
  73. package/.next/server/chunks/2959.js +1 -0
  74. package/.next/server/chunks/2995.js +1 -1
  75. package/.next/server/chunks/3332.js +1 -1
  76. package/.next/server/chunks/4514.js +3 -0
  77. package/.next/server/chunks/4812.js +1 -1
  78. package/.next/server/chunks/4925.js +1 -1
  79. package/.next/server/chunks/{3512.js → 5068.js} +2 -2
  80. package/.next/server/chunks/9098.js +1 -1
  81. package/.next/server/chunks/{6734.js → 9427.js} +1 -1
  82. package/.next/server/chunks/9538.js +1 -0
  83. package/.next/server/chunks/963.js +1 -0
  84. package/.next/server/middleware-build-manifest.js +1 -1
  85. package/.next/server/middleware-manifest.json +5 -5
  86. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  87. package/.next/server/pages/500.html +1 -1
  88. package/.next/server/server-reference-manifest.js +1 -1
  89. package/.next/server/server-reference-manifest.json +1 -1
  90. package/.next/static/chunks/2865-134f546f21ca4330.js +1 -0
  91. package/.next/static/chunks/4108.5abdb7812a13eafd.js +1 -0
  92. package/.next/static/chunks/5254-4196f25e56270de5.js +1 -0
  93. package/.next/static/chunks/5521-cbc665104c7e59d3.js +1 -0
  94. package/.next/static/chunks/8855-9b941d2b78f398ce.js +1 -0
  95. package/.next/static/chunks/8871-2948840b33c0863d.js +1 -0
  96. package/.next/static/chunks/app/layout-d4cf24375db6d793.js +1 -0
  97. package/.next/static/chunks/app/onboarding/page-7303664b62ccc24a.js +1 -0
  98. package/.next/static/chunks/app/page-97d312db91d569f7.js +1 -0
  99. package/.next/static/chunks/app/roots/[id]/chat/[topicId]/page-123f60a544619a3c.js +1 -0
  100. package/.next/static/chunks/app/roots/[id]/kb/[...slug]/{page-7d17b4e6a5231f56.js → page-e253597edb1b2440.js} +1 -1
  101. package/.next/static/chunks/app/roots/[id]/page-91a8de6a1c79f8a3.js +1 -0
  102. package/.next/static/chunks/app/roots/[id]/workflows/[wfId]/page-4300a52e163883df.js +1 -0
  103. package/.next/static/chunks/app/roots/new/page-6b104aad46a38173.js +1 -0
  104. package/.next/static/chunks/app/settings/page-afe1b80f7f45c5eb.js +1 -0
  105. package/.next/static/chunks/app/share/[id]/page-a5fb565bd892d4df.js +1 -0
  106. package/.next/static/chunks/app/utilities/[scope]/[id]/page-eb713a2b5209942c.js +1 -0
  107. package/.next/static/chunks/app/utilities/page-b7f30c151c42a27c.js +1 -0
  108. package/.next/static/chunks/{webpack-2b0eab4ccdf44f63.js → webpack-bddc3babcbc30dd7.js} +1 -1
  109. package/.next/static/css/60e9b6cdf1283e83.css +1 -0
  110. package/.next/trace +47 -47
  111. package/package.json +1 -2
  112. package/.next/server/chunks/1.js +0 -3
  113. package/.next/server/chunks/2192.js +0 -1
  114. package/.next/server/chunks/7215.js +0 -1
  115. package/.next/server/chunks/9944.js +0 -1
  116. package/.next/static/chunks/1082-326e649fb24d4945.js +0 -1
  117. package/.next/static/chunks/3736-f4e42d6d38be50b0.js +0 -1
  118. package/.next/static/chunks/4108.ca0bdf3cbf3c56cc.js +0 -1
  119. package/.next/static/chunks/7482-7ef26030a10ce14f.js +0 -1
  120. package/.next/static/chunks/8944-c4f2406ecd61094f.js +0 -1
  121. package/.next/static/chunks/9415-eb6b5d4c2de3a7c0.js +0 -1
  122. package/.next/static/chunks/app/layout-85eb1fd21dab0895.js +0 -1
  123. package/.next/static/chunks/app/onboarding/page-2013bd8124b9162e.js +0 -1
  124. package/.next/static/chunks/app/page-558a224e13ffb52c.js +0 -1
  125. package/.next/static/chunks/app/roots/[id]/chat/[topicId]/page-b42f03fd58669d12.js +0 -1
  126. package/.next/static/chunks/app/roots/[id]/page-4aab5266f432e37e.js +0 -1
  127. package/.next/static/chunks/app/roots/[id]/workflows/[wfId]/page-1ee3320bf5744efc.js +0 -1
  128. package/.next/static/chunks/app/roots/new/page-df8d2c1f0c64c37a.js +0 -1
  129. package/.next/static/chunks/app/settings/page-fdba798d9e243ad3.js +0 -1
  130. package/.next/static/chunks/app/share/[id]/page-818a451d05e08d26.js +0 -1
  131. package/.next/static/chunks/app/utilities/[scope]/[id]/page-2cee09cc2ab9b5e8.js +0 -1
  132. package/.next/static/chunks/app/utilities/page-44a51522b347f13e.js +0 -1
  133. package/.next/static/css/4b367c1d0fa99b78.css +0 -1
  134. package/packages/utilities/learn-anything/README.md +0 -41
  135. package/packages/utilities/learn-anything/actions/_json.ts +0 -191
  136. package/packages/utilities/learn-anything/actions/_store.ts +0 -248
  137. package/packages/utilities/learn-anything/actions/buildModule.ts +0 -488
  138. package/packages/utilities/learn-anything/actions/explainSelection.ts +0 -65
  139. package/packages/utilities/learn-anything/actions/generateOutline.ts +0 -170
  140. package/packages/utilities/learn-anything/actions/generateQuiz.ts +0 -72
  141. package/packages/utilities/learn-anything/actions/generateTrainer.ts +0 -106
  142. package/packages/utilities/learn-anything/actions/refreshCourseCard.ts +0 -76
  143. package/packages/utilities/learn-anything/actions/tutorAsk.ts +0 -93
  144. package/packages/utilities/learn-anything/article-view.tsx +0 -464
  145. package/packages/utilities/learn-anything/manifest.json +0 -42
  146. package/packages/utilities/learn-anything/ui.tsx +0 -1589
  147. /package/.next/static/{fhVNqfmJl5Mdfhyhg6orp → IGuuMcet1qtGZQCP2MEn4}/_buildManifest.js +0 -0
  148. /package/.next/static/{fhVNqfmJl5Mdfhyhg6orp → IGuuMcet1qtGZQCP2MEn4}/_ssgManifest.js +0 -0
@@ -1,464 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
- import ReactMarkdown, { type Components } from "react-markdown";
3
- import remarkGfm from "remark-gfm";
4
- import mermaid from "mermaid";
5
-
6
- /**
7
- * Self-contained article renderer for course modules. Owns:
8
- *
9
- * • Typography — no dependency on @tailwindcss/typography. Each
10
- * markdown element is mapped to an explicit class so headings,
11
- * blockquotes, lists, code blocks look like they belong in a
12
- * reading app (think "course on the web", not "raw textarea").
13
- *
14
- * • Mermaid diagrams — any `code` block with language=`mermaid` is
15
- * swapped for a `<pre class="mermaid">` shell after mount; we then
16
- * ask the global mermaid library to compile every such block on
17
- * screen into an SVG. Re-runs whenever the source content changes.
18
- */
19
- let mermaidReady = false;
20
- function ensureMermaid(): void {
21
- if (mermaidReady) return;
22
- mermaidReady = true;
23
- try {
24
- mermaid.initialize({
25
- startOnLoad: false,
26
- theme: "neutral",
27
- securityLevel: "loose", // utility iframe is already sandboxed
28
- fontFamily:
29
- "-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
30
- });
31
- } catch {
32
- /* mermaid init can be re-run safely; ignore early failures */
33
- }
34
- }
35
-
36
- export function ArticleView({
37
- source,
38
- onMouseUp,
39
- }: {
40
- source: string;
41
- onMouseUp?: () => void;
42
- }) {
43
- const ref = useRef<HTMLDivElement | null>(null);
44
- // Agents sometimes embed mermaid blocks without ```mermaid fences —
45
- // we wrap them on the fly so ReactMarkdown emits language-mermaid
46
- // <code> nodes that the `pre` override below picks up.
47
- const normalized = wrapBareMermaid(source);
48
-
49
- // Compile every <pre class="reflex-mermaid"> to inline SVG. Using
50
- // mermaid.render() per element (rather than mermaid.run) gives us
51
- // proper error capture per-block — we replace failed blocks with a
52
- // visible error message instead of leaving raw source on screen.
53
- useEffect(() => {
54
- ensureMermaid();
55
- const root = ref.current;
56
- if (!root) return;
57
- const nodes = Array.from(
58
- root.querySelectorAll<HTMLElement>("pre.reflex-mermaid:not(.reflex-mermaid-done)"),
59
- );
60
- if (nodes.length === 0) return;
61
- let cancelled = false;
62
- void (async () => {
63
- for (const node of nodes) {
64
- if (cancelled) return;
65
- const src = (node.dataset["src"] ?? node.textContent ?? "").trim();
66
- if (!src) continue;
67
- const id = `mmd-${Math.random().toString(36).slice(2, 9)}`;
68
- try {
69
- const { svg } = await mermaid.render(id, src);
70
- if (cancelled) return;
71
- node.innerHTML = svg;
72
- node.classList.add("reflex-mermaid-done");
73
- node.classList.remove("reflex-mermaid"); // shed the source styling
74
- node.style.fontFamily = "inherit";
75
- } catch (err) {
76
- const msg = err instanceof Error ? err.message : String(err);
77
- node.innerHTML = `<div class="text-xs text-red-600 not-italic">⚠ Failed to render diagram: ${escapeHtml(msg)}</div><pre class="mt-2 text-[11px] text-slate-700 whitespace-pre-wrap">${escapeHtml(src)}</pre>`;
78
- node.classList.add("reflex-mermaid-done");
79
- }
80
- }
81
- })();
82
- return () => {
83
- cancelled = true;
84
- };
85
- }, [normalized]);
86
-
87
- const [zoom, setZoom] = useState<{ src: string; alt: string } | null>(null);
88
- // Component map needs access to `setZoom`, so build it per-render
89
- // (memoed). The vast majority of nodes are static — only the `img`
90
- // override carries the click handler.
91
- const components = useMemo<Components>(
92
- () => ({
93
- ...MD_COMPONENTS,
94
- img: ({ src, alt }) => {
95
- const url = typeof src === "string" ? src : "";
96
- const safeAlt = typeof alt === "string" ? alt : "";
97
- if (!url) return null;
98
- return (
99
- // eslint-disable-next-line @next/next/no-img-element
100
- <img
101
- src={url}
102
- alt={safeAlt}
103
- title={safeAlt || "Open fullscreen"}
104
- loading="lazy"
105
- onClick={() => setZoom({ src: url, alt: safeAlt })}
106
- className="my-5 rounded-lg border bg-white max-w-full h-auto cursor-zoom-in transition hover:opacity-90"
107
- />
108
- );
109
- },
110
- }),
111
- [],
112
- );
113
- return (
114
- <div
115
- ref={ref}
116
- onMouseUp={onMouseUp}
117
- className="text-slate-900 [&_*::selection]:bg-violet-200"
118
- style={{ fontFamily: "Georgia, 'Times New Roman', serif" }}
119
- >
120
- <ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>
121
- {normalized}
122
- </ReactMarkdown>
123
- {zoom && (
124
- <ArticleImageLightbox
125
- src={zoom.src}
126
- alt={zoom.alt}
127
- onClose={() => setZoom(null)}
128
- />
129
- )}
130
- </div>
131
- );
132
- }
133
-
134
- /**
135
- * Reusable fullscreen lightbox. Exported so the rest of the learn-anything
136
- * UI (gallery card, etc.) can share the same overlay rather than each
137
- * surface rolling its own.
138
- */
139
- export function ArticleImageLightbox({
140
- src,
141
- alt,
142
- onClose,
143
- }: {
144
- src: string;
145
- alt: string;
146
- onClose: () => void;
147
- }) {
148
- const handleKey = useCallback(
149
- (e: KeyboardEvent) => {
150
- if (e.key === "Escape") onClose();
151
- },
152
- [onClose],
153
- );
154
- useEffect(() => {
155
- document.addEventListener("keydown", handleKey);
156
- const prev = document.body.style.overflow;
157
- document.body.style.overflow = "hidden";
158
- return () => {
159
- document.removeEventListener("keydown", handleKey);
160
- document.body.style.overflow = prev;
161
- };
162
- }, [handleKey]);
163
- return (
164
- <div
165
- onClick={onClose}
166
- role="dialog"
167
- aria-label={alt || "Image preview"}
168
- style={{
169
- position: "fixed",
170
- inset: 0,
171
- zIndex: 9999,
172
- display: "flex",
173
- alignItems: "center",
174
- justifyContent: "center",
175
- padding: "24px",
176
- background: "rgba(15, 23, 42, 0.85)",
177
- backdropFilter: "blur(4px)",
178
- cursor: "zoom-out",
179
- }}
180
- >
181
- <button
182
- type="button"
183
- onClick={(e) => {
184
- e.stopPropagation();
185
- onClose();
186
- }}
187
- aria-label="Close"
188
- style={{
189
- position: "absolute",
190
- top: 16,
191
- right: 16,
192
- height: 36,
193
- width: 36,
194
- borderRadius: 8,
195
- background: "rgba(255,255,255,0.92)",
196
- border: "1px solid rgba(15,23,42,0.1)",
197
- cursor: "pointer",
198
- fontSize: 18,
199
- }}
200
- >
201
- ×
202
- </button>
203
- {/* eslint-disable-next-line @next/next/no-img-element */}
204
- <img
205
- src={src}
206
- alt={alt}
207
- onClick={(e) => e.stopPropagation()}
208
- style={{
209
- maxHeight: "100%",
210
- maxWidth: "100%",
211
- objectFit: "contain",
212
- borderRadius: 12,
213
- boxShadow: "0 30px 60px rgba(0,0,0,0.5)",
214
- }}
215
- />
216
- {alt && (
217
- <div
218
- style={{
219
- position: "absolute",
220
- bottom: 24,
221
- left: 24,
222
- right: 24,
223
- textAlign: "center",
224
- color: "rgba(255,255,255,0.85)",
225
- fontSize: 13,
226
- pointerEvents: "none",
227
- }}
228
- >
229
- {alt}
230
- </div>
231
- )}
232
- </div>
233
- );
234
- }
235
-
236
- // ---------------------------------------------------------------------------
237
- // Typography map. Explicit per-element so we don't rely on @tailwindcss/
238
- // typography being available inside the utility's tailwind compile.
239
-
240
- const MD_COMPONENTS: Components = {
241
- h1: ({ children }) => (
242
- <h1 className="mt-8 mb-4 text-3xl font-bold tracking-tight text-slate-900 border-b border-slate-200 pb-2">
243
- {children}
244
- </h1>
245
- ),
246
- h2: ({ children }) => (
247
- <h2 className="mt-7 mb-3 text-2xl font-semibold tracking-tight text-slate-900">
248
- {children}
249
- </h2>
250
- ),
251
- h3: ({ children }) => (
252
- <h3 className="mt-6 mb-2 text-xl font-semibold tracking-tight text-slate-900">
253
- {children}
254
- </h3>
255
- ),
256
- h4: ({ children }) => (
257
- <h4 className="mt-5 mb-2 text-base font-semibold uppercase tracking-wider text-slate-700">
258
- {children}
259
- </h4>
260
- ),
261
- p: ({ children }) => (
262
- <p className="my-4 leading-7 text-slate-800 text-[15px]">{children}</p>
263
- ),
264
- strong: ({ children }) => (
265
- <strong className="font-semibold text-slate-900">{children}</strong>
266
- ),
267
- em: ({ children }) => <em className="italic text-slate-800">{children}</em>,
268
- blockquote: ({ children }) => (
269
- <blockquote className="my-5 border-l-4 border-violet-400 bg-violet-50/60 px-4 py-2 italic text-slate-700">
270
- {children}
271
- </blockquote>
272
- ),
273
- hr: () => <hr className="my-8 border-slate-200" />,
274
- a: ({ href, children }) => (
275
- <a
276
- href={href}
277
- target="_blank"
278
- rel="noopener noreferrer"
279
- className="text-violet-700 underline decoration-violet-300 underline-offset-2 hover:decoration-violet-600"
280
- >
281
- {children}
282
- </a>
283
- ),
284
- ul: ({ children }) => (
285
- <ul className="my-4 ml-6 list-disc space-y-1.5 text-[15px] text-slate-800 leading-7 marker:text-slate-400">
286
- {children}
287
- </ul>
288
- ),
289
- ol: ({ children }) => (
290
- <ol className="my-4 ml-6 list-decimal space-y-1.5 text-[15px] text-slate-800 leading-7 marker:text-slate-500 marker:font-semibold">
291
- {children}
292
- </ol>
293
- ),
294
- li: ({ children }) => <li className="pl-1">{children}</li>,
295
- code: ({ className, children }) => {
296
- const lang = /language-(\w+)/.exec(className ?? "")?.[1];
297
- // Inline code (no language) → small chip.
298
- if (!lang) {
299
- return (
300
- <code className="rounded bg-slate-100 px-1.5 py-0.5 text-[0.875em] font-mono text-violet-700">
301
- {children}
302
- </code>
303
- );
304
- }
305
- // Block code with a recognized fence — leave class for parent <pre>.
306
- return (
307
- <code className={`language-${lang} font-mono`}>{children}</code>
308
- );
309
- },
310
- pre: ({ children }) => {
311
- // Detect the mermaid case: the child <code> has lang=mermaid. Swap
312
- // <pre> for a marker class the effect later compiles into SVG.
313
- const child = Array.isArray(children) ? children[0] : children;
314
- if (
315
- child &&
316
- typeof child === "object" &&
317
- "props" in child &&
318
- typeof (child as { props?: { className?: string } }).props?.className ===
319
- "string"
320
- ) {
321
- const cls = (child as { props: { className: string } }).props.className;
322
- if (cls.includes("language-mermaid")) {
323
- const codeNode = child as { props: { children?: unknown } };
324
- const text = collectText(codeNode.props.children);
325
- // `data-src` carries the raw mermaid source so the effect
326
- // doesn't have to depend on `textContent` (which can pick up
327
- // ReactMarkdown's internal whitespace handling).
328
- return (
329
- <pre
330
- className="reflex-mermaid my-6 rounded-lg border border-slate-200 bg-slate-50 p-4 text-sm overflow-x-auto whitespace-pre"
331
- data-src={text}
332
- style={{ fontFamily: "ui-monospace, monospace" }}
333
- >
334
- {text}
335
- </pre>
336
- );
337
- }
338
- }
339
- return (
340
- <pre className="my-5 rounded-lg bg-slate-900 text-slate-50 px-4 py-3 text-sm overflow-x-auto leading-relaxed">
341
- {children}
342
- </pre>
343
- );
344
- },
345
- table: ({ children }) => (
346
- <div className="my-5 overflow-x-auto">
347
- <table className="w-full border-collapse text-sm">{children}</table>
348
- </div>
349
- ),
350
- thead: ({ children }) => (
351
- <thead className="bg-slate-100">{children}</thead>
352
- ),
353
- th: ({ children }) => (
354
- <th className="border border-slate-300 px-3 py-2 text-left font-semibold text-slate-700">
355
- {children}
356
- </th>
357
- ),
358
- td: ({ children }) => (
359
- <td className="border border-slate-200 px-3 py-2 align-top">{children}</td>
360
- ),
361
- // `img` is overridden per-render inside ArticleView (it needs setZoom).
362
- };
363
-
364
- /**
365
- * Wrap unfenced mermaid diagrams in ```mermaid …``` so ReactMarkdown
366
- * tags them as `language-mermaid` and the renderer pipeline catches
367
- * them. Detects blocks that START with a mermaid keyword (graph,
368
- * flowchart, sequenceDiagram, etc.) and run until a blank line or
369
- * the next heading.
370
- *
371
- * Already-fenced blocks pass through untouched.
372
- */
373
- const MERMAID_KEYWORDS = [
374
- "graph",
375
- "flowchart",
376
- "sequenceDiagram",
377
- "classDiagram",
378
- "stateDiagram",
379
- "stateDiagram-v2",
380
- "erDiagram",
381
- "gantt",
382
- "pie",
383
- "journey",
384
- "gitGraph",
385
- "mindmap",
386
- "timeline",
387
- "quadrantChart",
388
- "C4Context",
389
- "requirementDiagram",
390
- ];
391
-
392
- function wrapBareMermaid(text: string): string {
393
- if (!text) return text;
394
- const lines = text.split("\n");
395
- const out: string[] = [];
396
- let i = 0;
397
- let inFence = false;
398
- while (i < lines.length) {
399
- const line = lines[i]!;
400
- // Track fenced state so we never wrap inside an existing code block.
401
- if (/^```/.test(line)) {
402
- inFence = !inFence;
403
- out.push(line);
404
- i++;
405
- continue;
406
- }
407
- if (!inFence && isMermaidStart(line)) {
408
- // Collect lines until blank line, heading, or another fence start.
409
- const block: string[] = [line];
410
- let j = i + 1;
411
- while (j < lines.length) {
412
- const l = lines[j]!;
413
- if (l.trim() === "") break;
414
- if (/^#{1,6}\s/.test(l)) break;
415
- if (/^```/.test(l)) break;
416
- block.push(l);
417
- j++;
418
- }
419
- out.push("```mermaid");
420
- out.push(...block);
421
- out.push("```");
422
- i = j;
423
- continue;
424
- }
425
- out.push(line);
426
- i++;
427
- }
428
- return out.join("\n");
429
- }
430
-
431
- function isMermaidStart(line: string): boolean {
432
- const trimmed = line.trim();
433
- if (!trimmed) return false;
434
- for (const kw of MERMAID_KEYWORDS) {
435
- if (trimmed === kw) return true;
436
- if (trimmed.startsWith(kw + " ")) return true;
437
- // `graph LR`, `flowchart TD` etc.
438
- if (
439
- trimmed.startsWith(kw) &&
440
- /^[A-Z]{2}$/.test(trimmed.slice(kw.length).trim())
441
- ) {
442
- return true;
443
- }
444
- }
445
- return false;
446
- }
447
-
448
- function escapeHtml(s: string): string {
449
- return s
450
- .replace(/&/g, "&amp;")
451
- .replace(/</g, "&lt;")
452
- .replace(/>/g, "&gt;")
453
- .replace(/"/g, "&quot;");
454
- }
455
-
456
- function collectText(children: unknown): string {
457
- if (typeof children === "string") return children;
458
- if (Array.isArray(children)) return children.map(collectText).join("");
459
- if (children && typeof children === "object" && "props" in children) {
460
- const props = (children as { props?: { children?: unknown } }).props;
461
- return collectText(props?.children);
462
- }
463
- return "";
464
- }
@@ -1,42 +0,0 @@
1
- {
2
- "id": "learn-anything",
3
- "name": "🎓 Learn Anything",
4
- "version": "0.4.7",
5
- "description": "Universal AI tutor: courses tailored to your level with content, quizzes, and trainers",
6
- "author": "reflex-org",
7
- "category": "study",
8
- "ui": "ui.tsx",
9
- "icon": "lucide:GraduationCap",
10
- "card": {
11
- "kind": "kpi",
12
- "title": "🎓 Learning",
13
- "data": {
14
- "items": [
15
- { "label": "Active courses", "value": "0" },
16
- { "label": "Progress", "value": "—", "hint": "average across courses" }
17
- ]
18
- }
19
- },
20
- "serverActions": [
21
- { "name": "tutorAsk", "entry": "actions/tutorAsk.ts", "timeoutMs": 120000 },
22
- { "name": "generateOutline", "entry": "actions/generateOutline.ts", "timeoutMs": 300000 },
23
- { "name": "buildModule", "entry": "actions/buildModule.ts", "timeoutMs": 480000 },
24
- { "name": "generateQuiz", "entry": "actions/generateQuiz.ts", "timeoutMs": 180000 },
25
- { "name": "explainSelection", "entry": "actions/explainSelection.ts", "timeoutMs": 120000 },
26
- { "name": "generateTrainer", "entry": "actions/generateTrainer.ts", "timeoutMs": 480000 },
27
- { "name": "refreshCourseCard", "entry": "actions/refreshCourseCard.ts", "timeoutMs": 30000 }
28
- ],
29
- "permissions": {
30
- "llm": { "tasks": ["chat", "quick"] },
31
- "kb": { "read": true, "write": true, "kinds": ["course", "course-module", "course-trainer", "course-note"] },
32
- "fs": { "sandbox": true },
33
- "web": {
34
- "fetch": { "domains": ["wikipedia.org", "en.wikipedia.org", "ru.wikipedia.org", "developer.mozilla.org", "youtube.com", "youtu.be", "github.com", "raw.githubusercontent.com", "stackoverflow.com", "medium.com"] },
35
- "search": true
36
- },
37
- "audit": { "write": true },
38
- "workers": { "enabled": true, "maxConcurrent": 3 },
39
- "agent": { "invoke": true },
40
- "images": { "generate": true, "search": true, "attach": true }
41
- }
42
- }