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.
- package/package.json +4 -1
- package/src/ruvocal/.claude-flow/data/pending-insights.jsonl +25 -0
- package/src/ruvocal/.claude-flow/neural/stats.json +6 -0
- package/src/ruvocal/.dockerignore +5 -1
- package/src/ruvocal/.gcloudignore +18 -0
- package/src/ruvocal/README.md +107 -133
- package/src/ruvocal/cloudbuild.yaml +68 -0
- package/src/ruvocal/config/branding.env.example +19 -0
- package/src/ruvocal/mcp-bridge/index.js +15 -1
- package/src/ruvocal/src/lib/components/FoundationBackground.svelte +242 -0
- package/src/ruvocal/src/lib/components/NavMenu.svelte +18 -0
- package/src/ruvocal/src/lib/components/RufloHelpModal.svelte +411 -0
- package/src/ruvocal/src/lib/components/chat/ChatWindow.svelte +122 -4
- package/src/ruvocal/src/lib/components/wasm/GalleryPanel.svelte +357 -0
- package/src/ruvocal/src/lib/constants/mcpExamples.ts +56 -77
- package/src/ruvocal/src/lib/constants/routerExamples.ts +51 -127
- package/src/ruvocal/src/lib/constants/rvagentPresets.ts +206 -0
- package/src/ruvocal/src/lib/server/textGeneration/mcp/wasmTools.test.ts +633 -0
- package/src/ruvocal/src/lib/stores/mcpServers.ts +195 -6
- package/src/ruvocal/src/lib/stores/wasmMcp.ts +472 -0
- package/src/ruvocal/src/lib/types/Settings.ts +7 -0
- package/src/ruvocal/src/lib/types/Tool.ts +4 -1
- package/src/ruvocal/src/lib/wasm/idb.ts +438 -0
- package/src/ruvocal/src/lib/wasm/index.ts +1213 -0
- package/src/ruvocal/src/lib/wasm/tests/wasm-capabilities.test.ts +565 -0
- package/src/ruvocal/src/lib/wasm/wasm.worker.ts +332 -0
- package/src/ruvocal/src/lib/wasm/workerClient.ts +166 -0
- package/src/ruvocal/static/wasm/rvagent_wasm.js +1539 -0
- 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;
|