ruflo 3.6.12 → 3.6.14

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 (29) hide show
  1. package/package.json +4 -1
  2. package/src/ruvocal/.claude-flow/data/pending-insights.jsonl +25 -0
  3. package/src/ruvocal/.claude-flow/neural/stats.json +6 -0
  4. package/src/ruvocal/.dockerignore +5 -1
  5. package/src/ruvocal/.gcloudignore +18 -0
  6. package/src/ruvocal/README.md +107 -133
  7. package/src/ruvocal/cloudbuild.yaml +68 -0
  8. package/src/ruvocal/config/branding.env.example +19 -0
  9. package/src/ruvocal/mcp-bridge/index.js +15 -1
  10. package/src/ruvocal/src/lib/components/FoundationBackground.svelte +242 -0
  11. package/src/ruvocal/src/lib/components/NavMenu.svelte +18 -0
  12. package/src/ruvocal/src/lib/components/RufloHelpModal.svelte +411 -0
  13. package/src/ruvocal/src/lib/components/chat/ChatWindow.svelte +122 -4
  14. package/src/ruvocal/src/lib/components/wasm/GalleryPanel.svelte +357 -0
  15. package/src/ruvocal/src/lib/constants/mcpExamples.ts +56 -77
  16. package/src/ruvocal/src/lib/constants/routerExamples.ts +51 -127
  17. package/src/ruvocal/src/lib/constants/rvagentPresets.ts +206 -0
  18. package/src/ruvocal/src/lib/server/textGeneration/mcp/wasmTools.test.ts +633 -0
  19. package/src/ruvocal/src/lib/stores/mcpServers.ts +195 -6
  20. package/src/ruvocal/src/lib/stores/wasmMcp.ts +472 -0
  21. package/src/ruvocal/src/lib/types/Settings.ts +7 -0
  22. package/src/ruvocal/src/lib/types/Tool.ts +4 -1
  23. package/src/ruvocal/src/lib/wasm/idb.ts +438 -0
  24. package/src/ruvocal/src/lib/wasm/index.ts +1213 -0
  25. package/src/ruvocal/src/lib/wasm/tests/wasm-capabilities.test.ts +565 -0
  26. package/src/ruvocal/src/lib/wasm/wasm.worker.ts +332 -0
  27. package/src/ruvocal/src/lib/wasm/workerClient.ts +166 -0
  28. package/src/ruvocal/static/wasm/rvagent_wasm.js +1539 -0
  29. package/src/ruvocal/static/wasm/rvagent_wasm_bg.wasm +0 -0
@@ -0,0 +1,242 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from "svelte";
3
+ import { browser } from "$app/environment";
4
+
5
+ interface Props {
6
+ opacity?: number;
7
+ }
8
+
9
+ let { opacity = 0.6 }: Props = $props();
10
+
11
+ let canvas: HTMLCanvasElement | undefined = $state();
12
+ let animationFrame: number;
13
+
14
+ // Mathematical glyphs for Foundation aesthetic
15
+ const GLYPHS = ['∑', '∫', '∂', '∞', '∇', 'Δ', 'Ψ', 'Ω', 'π', 'λ', 'θ', 'φ', 'ξ', '∈', '∀', '∃', '⊕', '⊗', '≡', '≈'];
16
+
17
+ interface Particle {
18
+ x: number;
19
+ y: number;
20
+ vx: number;
21
+ vy: number;
22
+ size: number;
23
+ opacity: number;
24
+ glyph?: string;
25
+ isGlyph: boolean;
26
+ phase: number;
27
+ speed: number;
28
+ }
29
+
30
+ interface Connection {
31
+ from: number;
32
+ to: number;
33
+ opacity: number;
34
+ }
35
+
36
+ let particles: Particle[] = [];
37
+ let connections: Connection[] = [];
38
+ let time = 0;
39
+ let mouseX = 0.5;
40
+ let mouseY = 0.5;
41
+
42
+ function initParticles(width: number, height: number) {
43
+ particles = [];
44
+ const particleCount = Math.floor((width * height) / 15000);
45
+ const glyphCount = Math.floor(particleCount * 0.15);
46
+
47
+ for (let i = 0; i < particleCount; i++) {
48
+ const isGlyph = i < glyphCount;
49
+ particles.push({
50
+ x: Math.random() * width,
51
+ y: Math.random() * height,
52
+ vx: (Math.random() - 0.5) * 0.3,
53
+ vy: (Math.random() - 0.5) * 0.3,
54
+ size: isGlyph ? 12 + Math.random() * 8 : 1 + Math.random() * 2,
55
+ opacity: 0.1 + Math.random() * 0.5,
56
+ glyph: isGlyph ? GLYPHS[Math.floor(Math.random() * GLYPHS.length)] : undefined,
57
+ isGlyph,
58
+ phase: Math.random() * Math.PI * 2,
59
+ speed: 0.5 + Math.random() * 1.5,
60
+ });
61
+ }
62
+ }
63
+
64
+ function updateConnections() {
65
+ connections = [];
66
+ const maxDist = 120;
67
+
68
+ for (let i = 0; i < particles.length; i++) {
69
+ for (let j = i + 1; j < particles.length; j++) {
70
+ const dx = particles[i].x - particles[j].x;
71
+ const dy = particles[i].y - particles[j].y;
72
+ const dist = Math.sqrt(dx * dx + dy * dy);
73
+
74
+ if (dist < maxDist) {
75
+ connections.push({
76
+ from: i,
77
+ to: j,
78
+ opacity: (1 - dist / maxDist) * 0.15,
79
+ });
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ function animate() {
86
+ if (!canvas) return;
87
+ const ctx = canvas.getContext("2d");
88
+ if (!ctx) return;
89
+
90
+ const width = canvas.width;
91
+ const height = canvas.height;
92
+
93
+ // Clear with fade effect
94
+ ctx.fillStyle = "rgba(2, 2, 5, 0.15)";
95
+ ctx.fillRect(0, 0, width, height);
96
+
97
+ time += 0.008;
98
+
99
+ // Update particles
100
+ particles.forEach((p, i) => {
101
+ // Mouse influence
102
+ const dx = mouseX * width - p.x;
103
+ const dy = mouseY * height - p.y;
104
+ const dist = Math.sqrt(dx * dx + dy * dy);
105
+ if (dist < 200) {
106
+ const force = (200 - dist) / 200 * 0.02;
107
+ p.vx += dx * force * 0.01;
108
+ p.vy += dy * force * 0.01;
109
+ }
110
+
111
+ // Drift
112
+ p.x += p.vx + Math.sin(time * p.speed + p.phase) * 0.2;
113
+ p.y += p.vy + Math.cos(time * p.speed + p.phase) * 0.2;
114
+
115
+ // Damping
116
+ p.vx *= 0.99;
117
+ p.vy *= 0.99;
118
+
119
+ // Wrap around
120
+ if (p.x < -50) p.x = width + 50;
121
+ if (p.x > width + 50) p.x = -50;
122
+ if (p.y < -50) p.y = height + 50;
123
+ if (p.y > height + 50) p.y = -50;
124
+
125
+ // Pulse opacity
126
+ const pulseOpacity = p.opacity * (0.5 + Math.sin(time * 2 + p.phase) * 0.5);
127
+
128
+ if (p.isGlyph && p.glyph) {
129
+ // Draw glyph
130
+ ctx.save();
131
+ ctx.font = `${p.size}px "SF Mono", "Fira Code", monospace`;
132
+ ctx.fillStyle = `rgba(232, 166, 52, ${pulseOpacity * 0.6})`;
133
+ ctx.shadowColor = "#e8a634";
134
+ ctx.shadowBlur = 8;
135
+ ctx.fillText(p.glyph, p.x, p.y);
136
+ ctx.restore();
137
+ } else {
138
+ // Draw particle
139
+ ctx.beginPath();
140
+ ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
141
+ ctx.fillStyle = `rgba(232, 166, 52, ${pulseOpacity})`;
142
+ ctx.fill();
143
+ }
144
+ });
145
+
146
+ // Update connections periodically
147
+ if (Math.floor(time * 10) % 5 === 0) {
148
+ updateConnections();
149
+ }
150
+
151
+ // Draw connections
152
+ connections.forEach((c) => {
153
+ const p1 = particles[c.from];
154
+ const p2 = particles[c.to];
155
+ if (!p1 || !p2) return;
156
+ ctx.beginPath();
157
+ ctx.moveTo(p1.x, p1.y);
158
+ ctx.lineTo(p2.x, p2.y);
159
+ ctx.strokeStyle = `rgba(232, 166, 52, ${c.opacity})`;
160
+ ctx.lineWidth = 0.5;
161
+ ctx.stroke();
162
+ });
163
+
164
+ // Draw orbital rings
165
+ const centerX = width / 2;
166
+ const centerY = height / 2;
167
+ const rings = [
168
+ { radius: 180, rotation: time * 0.3, opacity: 0.08 },
169
+ { radius: 250, rotation: -time * 0.2, opacity: 0.06 },
170
+ { radius: 320, rotation: time * 0.15, opacity: 0.04 },
171
+ ];
172
+
173
+ rings.forEach((ring) => {
174
+ ctx.save();
175
+ ctx.translate(centerX, centerY);
176
+ ctx.rotate(ring.rotation);
177
+ ctx.beginPath();
178
+ ctx.ellipse(0, 0, ring.radius, ring.radius * 0.3, 0, 0, Math.PI * 2);
179
+ ctx.strokeStyle = `rgba(232, 166, 52, ${ring.opacity})`;
180
+ ctx.lineWidth = 1;
181
+ ctx.stroke();
182
+ ctx.restore();
183
+ });
184
+
185
+ // Central core glow
186
+ const coreGlow = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, 100);
187
+ coreGlow.addColorStop(0, `rgba(232, 166, 52, ${0.15 + Math.sin(time * 3) * 0.05})`);
188
+ coreGlow.addColorStop(0.5, "rgba(232, 166, 52, 0.02)");
189
+ coreGlow.addColorStop(1, "transparent");
190
+ ctx.fillStyle = coreGlow;
191
+ ctx.beginPath();
192
+ ctx.arc(centerX, centerY, 100, 0, Math.PI * 2);
193
+ ctx.fill();
194
+
195
+ animationFrame = requestAnimationFrame(animate);
196
+ }
197
+
198
+ function handleResize() {
199
+ if (!canvas) return;
200
+ canvas.width = window.innerWidth;
201
+ canvas.height = window.innerHeight;
202
+ initParticles(canvas.width, canvas.height);
203
+ }
204
+
205
+ function handleMouseMove(e: MouseEvent) {
206
+ mouseX = e.clientX / window.innerWidth;
207
+ mouseY = e.clientY / window.innerHeight;
208
+ }
209
+
210
+ onMount(() => {
211
+ if (!browser || !canvas) return;
212
+ handleResize();
213
+ animate();
214
+ window.addEventListener("resize", handleResize);
215
+ window.addEventListener("mousemove", handleMouseMove);
216
+ });
217
+
218
+ onDestroy(() => {
219
+ if (!browser) return;
220
+ cancelAnimationFrame(animationFrame);
221
+ window.removeEventListener("resize", handleResize);
222
+ window.removeEventListener("mousemove", handleMouseMove);
223
+ });
224
+ </script>
225
+
226
+ <canvas
227
+ bind:this={canvas}
228
+ class="foundation-bg"
229
+ style="opacity: {opacity}"
230
+ ></canvas>
231
+
232
+ <style>
233
+ .foundation-bg {
234
+ position: fixed;
235
+ top: 0;
236
+ left: 0;
237
+ width: 100%;
238
+ height: 100%;
239
+ z-index: 0;
240
+ pointer-events: none;
241
+ }
242
+ </style>
@@ -32,6 +32,7 @@
32
32
  import { isPro } from "$lib/stores/isPro";
33
33
  import IconPro from "$lib/components/icons/IconPro.svelte";
34
34
  import MCPServerManager from "./mcp/MCPServerManager.svelte";
35
+ import RufloHelpModal from "./RufloHelpModal.svelte";
35
36
 
36
37
  const publicConfig = usePublicConfig();
37
38
  const client = useAPIClient();
@@ -117,6 +118,7 @@
117
118
  let isDark = $state(false);
118
119
  let unsubscribeTheme: (() => void) | undefined;
119
120
  let showMcpModal = $state(false);
121
+ let showHelpModal = $state(false);
120
122
 
121
123
  if (browser) {
122
124
  unsubscribeTheme = subscribeToTheme(({ isDark: nextIsDark }) => {
@@ -247,6 +249,18 @@
247
249
  >
248
250
  Settings
249
251
  </a>
252
+ <button
253
+ onclick={() => (showHelpModal = true)}
254
+ aria-label="Open help and tool documentation"
255
+ title="RuFlo capabilities & tool docs"
256
+ class="flex size-9 min-w-[1.5em] flex-none items-center justify-center rounded-lg p-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
257
+ >
258
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4">
259
+ <circle cx="12" cy="12" r="10" />
260
+ <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
261
+ <line x1="12" y1="17" x2="12.01" y2="17" />
262
+ </svg>
263
+ </button>
250
264
  <button
251
265
  onclick={() => {
252
266
  switchTheme();
@@ -269,6 +283,10 @@
269
283
  <MCPServerManager onclose={() => (showMcpModal = false)} />
270
284
  {/if}
271
285
 
286
+ {#if showHelpModal}
287
+ <RufloHelpModal onclose={() => (showHelpModal = false)} />
288
+ {/if}
289
+
272
290
  <style>
273
291
  .quantum-dot {
274
292
  display: block;