mirror of
https://github.com/samvallad33/vestige.git
synced 2026-06-06 20:15:15 +02:00
feat: Vestige v2.0.0 "Cognitive Leap" — 3D dashboard, HyDE search, WebSocket events
The biggest release in Vestige history. Complete visual and cognitive overhaul. Dashboard: - SvelteKit 2 + Three.js 3D neural visualization at localhost:3927/dashboard - 7 interactive pages: Graph, Memories, Timeline, Feed, Explore, Intentions, Stats - WebSocket event bus with 16 event types, real-time 3D animations - Bloom post-processing, GPU instanced rendering, force-directed layout - Dream visualization mode, FSRS retention curves, command palette (Cmd+K) - Keyboard shortcuts, responsive mobile layout, PWA installable - Single binary deployment via include_dir! (22MB) Engine: - HyDE query expansion (intent classification + 3-5 semantic variants + centroid) - fastembed 5.11 with optional Nomic v2 MoE + Qwen3 reranker + Metal GPU - Emotional memory module (#29) - Criterion benchmark suite Backend: - Axum WebSocket at /ws with heartbeat + event broadcast - 7 new REST endpoints for cognitive operations - Event emission from MCP tools via shared broadcast channel - CORS for SvelteKit dev mode Distribution: - GitHub issue templates (bug report, feature request) - CHANGELOG with comprehensive v2.0 release notes - README updated with dashboard docs, architecture diagram, comparison table 734 tests passing, zero warnings, 22MB release binary. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
26cee040a5
commit
c2d28f3433
321 changed files with 32695 additions and 4727 deletions
|
|
@ -0,0 +1,44 @@
|
|||
import { g as getContext, c as escape_html } from "../../chunks/index.js";
|
||||
import "../../chunks/state.svelte.js";
|
||||
import "@sveltejs/kit/internal";
|
||||
import "../../chunks/exports.js";
|
||||
import "../../chunks/utils2.js";
|
||||
import { w as writable } from "../../chunks/index2.js";
|
||||
import "@sveltejs/kit/internal/server";
|
||||
import "../../chunks/root.js";
|
||||
function create_updated_store() {
|
||||
const { set, subscribe } = writable(false);
|
||||
{
|
||||
return {
|
||||
subscribe,
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
check: async () => false
|
||||
};
|
||||
}
|
||||
}
|
||||
const stores = {
|
||||
updated: /* @__PURE__ */ create_updated_store()
|
||||
};
|
||||
({
|
||||
check: stores.updated.check
|
||||
});
|
||||
function context() {
|
||||
return getContext("__request__");
|
||||
}
|
||||
const page$1 = {
|
||||
get error() {
|
||||
return context().page.error;
|
||||
},
|
||||
get status() {
|
||||
return context().page.status;
|
||||
}
|
||||
};
|
||||
const page = page$1;
|
||||
function Error$1($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
$$renderer2.push(`<h1>${escape_html(page.status)}</h1> <p>${escape_html(page.error?.message)}</p>`);
|
||||
});
|
||||
}
|
||||
export {
|
||||
Error$1 as default
|
||||
};
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
function _layout($$renderer, $$props) {
|
||||
let { children } = $$props;
|
||||
children($$renderer);
|
||||
$$renderer.push(`<!---->`);
|
||||
}
|
||||
export {
|
||||
_layout as default
|
||||
};
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import { e as ensure_array_like, b as attr_class, c as escape_html, a as attr, d as stringify } from "../../../../chunks/index.js";
|
||||
function _page($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let searchQuery = "";
|
||||
let mode = "associations";
|
||||
let importanceText = "";
|
||||
const MODE_INFO = {
|
||||
associations: {
|
||||
icon: "◎",
|
||||
desc: "Spreading activation — find related memories via graph traversal"
|
||||
},
|
||||
chains: {
|
||||
icon: "⟿",
|
||||
desc: "Build reasoning path from source to target memory"
|
||||
},
|
||||
bridges: {
|
||||
icon: "⬡",
|
||||
desc: "Find connecting memories between two concepts"
|
||||
}
|
||||
};
|
||||
$$renderer2.push(`<div class="p-6 max-w-5xl mx-auto space-y-8"><h1 class="text-xl text-bright font-semibold">Explore Connections</h1> <div class="grid grid-cols-3 gap-2"><!--[-->`);
|
||||
const each_array = ensure_array_like(["associations", "chains", "bridges"]);
|
||||
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
|
||||
let m = each_array[$$index];
|
||||
$$renderer2.push(`<button${attr_class(`flex flex-col items-center gap-1 p-3 rounded-lg text-sm transition ${stringify(mode === m ? "bg-synapse/15 text-synapse-glow border border-synapse/40" : "bg-surface/30 text-dim border border-subtle/20 hover:border-subtle/40")}`)}><span class="text-xl">${escape_html(MODE_INFO[m].icon)}</span> <span class="font-medium">${escape_html(m.charAt(0).toUpperCase() + m.slice(1))}</span> <span class="text-[10px] text-muted text-center">${escape_html(MODE_INFO[m].desc)}</span></button>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> <div class="space-y-3"><label class="text-xs text-dim font-medium">Source Memory</label> <div class="flex gap-2"><input type="text" placeholder="Search for a memory to explore from..."${attr("value", searchQuery)} class="flex-1 px-4 py-2.5 bg-surface border border-subtle/40 rounded-lg text-text text-sm placeholder:text-muted focus:outline-none focus:border-synapse/60 transition"/> <button class="px-4 py-2.5 bg-synapse/20 border border-synapse/40 text-synapse-glow text-sm rounded-lg hover:bg-synapse/30 transition">Find</button></div></div> `);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--> `);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--> `);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--> <div class="pt-8 border-t border-subtle/20"><h2 class="text-lg text-bright font-semibold mb-4">Importance Scorer</h2> <p class="text-xs text-muted mb-3">4-channel neuroscience scoring: novelty, arousal, reward, attention</p> <textarea placeholder="Paste any text to score its importance..." class="w-full h-24 px-4 py-3 bg-surface border border-subtle/40 rounded-lg text-text text-sm placeholder:text-muted resize-none focus:outline-none focus:border-synapse/60 transition">`);
|
||||
const $$body = escape_html(importanceText);
|
||||
if ($$body) {
|
||||
$$renderer2.push(`${$$body}`);
|
||||
}
|
||||
$$renderer2.push(`</textarea> <button class="mt-2 px-4 py-2 bg-dream/20 border border-dream/40 text-dream-glow text-sm rounded-lg hover:bg-dream/30 transition">Score</button> `);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div></div>`);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_page as default
|
||||
};
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
import { c as escape_html, s as store_get, e as ensure_array_like, ac as attr_style, d as stringify, f as unsubscribe_stores } from "../../../../chunks/index.js";
|
||||
import { e as eventFeed } from "../../../../chunks/websocket.js";
|
||||
import { E as EVENT_TYPE_COLORS } from "../../../../chunks/index3.js";
|
||||
function _page($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
var $$store_subs;
|
||||
function formatTime(ts) {
|
||||
return new Date(ts).toLocaleTimeString();
|
||||
}
|
||||
function eventIcon(type) {
|
||||
const icons = {
|
||||
MemoryCreated: "+",
|
||||
MemoryUpdated: "~",
|
||||
MemoryDeleted: "×",
|
||||
MemoryPromoted: "↑",
|
||||
MemoryDemoted: "↓",
|
||||
SearchPerformed: "◎",
|
||||
DreamStarted: "◈",
|
||||
DreamProgress: "◈",
|
||||
DreamCompleted: "◈",
|
||||
ConsolidationStarted: "◉",
|
||||
ConsolidationCompleted: "◉",
|
||||
RetentionDecayed: "↘",
|
||||
ConnectionDiscovered: "━",
|
||||
ActivationSpread: "◬",
|
||||
ImportanceScored: "◫",
|
||||
Heartbeat: "♡"
|
||||
};
|
||||
return icons[type] || "·";
|
||||
}
|
||||
function eventSummary(event) {
|
||||
const d = event.data;
|
||||
switch (event.type) {
|
||||
case "MemoryCreated":
|
||||
return `New ${d.node_type}: "${String(d.content_preview).slice(0, 60)}..."`;
|
||||
case "SearchPerformed":
|
||||
return `Searched "${d.query}" → ${d.result_count} results (${d.duration_ms}ms)`;
|
||||
case "DreamStarted":
|
||||
return `Dream started with ${d.memory_count} memories`;
|
||||
case "DreamCompleted":
|
||||
return `Dream complete: ${d.connections_found} connections, ${d.insights_generated} insights (${d.duration_ms}ms)`;
|
||||
case "ConsolidationStarted":
|
||||
return "Consolidation cycle started";
|
||||
case "ConsolidationCompleted":
|
||||
return `Consolidated ${d.nodes_processed} nodes, ${d.decay_applied} decayed (${d.duration_ms}ms)`;
|
||||
case "ConnectionDiscovered":
|
||||
return `Connection: ${String(d.connection_type)} (weight: ${Number(d.weight).toFixed(2)})`;
|
||||
case "ImportanceScored":
|
||||
return `Scored ${Number(d.composite_score).toFixed(2)}: "${String(d.content_preview).slice(0, 50)}..."`;
|
||||
case "MemoryPromoted":
|
||||
return `Promoted → ${(Number(d.new_retention) * 100).toFixed(0)}% retention`;
|
||||
case "MemoryDemoted":
|
||||
return `Demoted → ${(Number(d.new_retention) * 100).toFixed(0)}% retention`;
|
||||
default:
|
||||
return JSON.stringify(d).slice(0, 100);
|
||||
}
|
||||
}
|
||||
$$renderer2.push(`<div class="p-6 max-w-4xl mx-auto space-y-6"><div class="flex items-center justify-between"><h1 class="text-xl text-bright font-semibold">Live Feed</h1> <div class="flex gap-3"><span class="text-dim text-sm">${escape_html(store_get($$store_subs ??= {}, "$eventFeed", eventFeed).length)} events</span> <button class="text-xs text-muted hover:text-text transition">Clear</button></div></div> `);
|
||||
if (store_get($$store_subs ??= {}, "$eventFeed", eventFeed).length === 0) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<div class="text-center py-20 text-dim"><div class="text-4xl mb-4">◉</div> <p>Waiting for cognitive events...</p> <p class="text-sm text-muted mt-2">Events appear here in real-time as Vestige thinks.</p></div>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
$$renderer2.push(`<div class="space-y-2"><!--[-->`);
|
||||
const each_array = ensure_array_like(store_get($$store_subs ??= {}, "$eventFeed", eventFeed));
|
||||
for (let i = 0, $$length = each_array.length; i < $$length; i++) {
|
||||
let event = each_array[i];
|
||||
$$renderer2.push(`<div class="flex items-start gap-3 p-3 bg-surface/40 border border-subtle/15 rounded-lg hover:border-subtle/30 transition-all duration-200"${attr_style(`border-left: 3px solid ${stringify(EVENT_TYPE_COLORS[event.type] || "#6b7280")}`)}><div class="w-6 h-6 rounded flex items-center justify-center text-xs flex-shrink-0"${attr_style(`background: ${stringify(EVENT_TYPE_COLORS[event.type] || "#6b7280")}20; color: ${stringify(EVENT_TYPE_COLORS[event.type] || "#6b7280")}`)}>${escape_html(eventIcon(event.type))}</div> <div class="flex-1 min-w-0"><div class="flex items-center gap-2 mb-0.5"><span class="text-xs font-medium"${attr_style(`color: ${stringify(EVENT_TYPE_COLORS[event.type] || "#6b7280")}`)}>${escape_html(event.type)}</span> `);
|
||||
if (event.data.timestamp) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<span class="text-xs text-muted">${escape_html(formatTime(String(event.data.timestamp)))}</span>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> <p class="text-sm text-dim">${escape_html(eventSummary(event))}</p></div></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
if ($$store_subs) unsubscribe_stores($$store_subs);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_page as default
|
||||
};
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
import { ad as ssr_context, a as attr, b as attr_class, c as escape_html, s as store_get, f as unsubscribe_stores, d as stringify } from "../../../../chunks/index.js";
|
||||
import { a as api } from "../../../../chunks/api.js";
|
||||
import { e as eventFeed } from "../../../../chunks/websocket.js";
|
||||
function onDestroy(fn) {
|
||||
/** @type {SSRContext} */
|
||||
ssr_context.r.on_destroy(fn);
|
||||
}
|
||||
function Graph3D($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let animationId;
|
||||
onDestroy(() => {
|
||||
cancelAnimationFrame(animationId);
|
||||
window.removeEventListener("resize", onResize);
|
||||
});
|
||||
function onResize() {
|
||||
return;
|
||||
}
|
||||
$$renderer2.push(`<div class="w-full h-full"></div>`);
|
||||
});
|
||||
}
|
||||
function _page($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
var $$store_subs;
|
||||
let graphData = null;
|
||||
let loading = true;
|
||||
let error = "";
|
||||
let isDreaming = false;
|
||||
let searchQuery = "";
|
||||
let maxNodes = 150;
|
||||
async function loadGraph(query, centerId) {
|
||||
loading = true;
|
||||
error = "";
|
||||
try {
|
||||
graphData = await api.graph({
|
||||
max_nodes: maxNodes,
|
||||
depth: 3,
|
||||
query: query || void 0,
|
||||
center_id: centerId || void 0
|
||||
});
|
||||
} catch {
|
||||
error = "No memories yet. Start using Vestige to populate your graph.";
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
$$renderer2.push(`<div class="h-full relative">`);
|
||||
if (loading) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<div class="h-full flex items-center justify-center"><div class="text-center space-y-4"><div class="w-16 h-16 mx-auto rounded-full border-2 border-synapse/30 border-t-synapse animate-spin"></div> <p class="text-dim text-sm">Loading memory graph...</p></div></div>`);
|
||||
} else if (error) {
|
||||
$$renderer2.push("<!--[1-->");
|
||||
$$renderer2.push(`<div class="h-full flex items-center justify-center"><div class="text-center space-y-4 max-w-md px-8"><div class="text-5xl opacity-30">◎</div> <h2 class="text-xl text-bright">Your Mind Awaits</h2> <p class="text-dim text-sm">${escape_html(error)}</p></div></div>`);
|
||||
} else if (graphData) {
|
||||
$$renderer2.push("<!--[2-->");
|
||||
Graph3D($$renderer2, {
|
||||
nodes: graphData.nodes,
|
||||
edges: graphData.edges,
|
||||
centerId: graphData.center_id,
|
||||
events: store_get($$store_subs ??= {}, "$eventFeed", eventFeed)
|
||||
});
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--> <div class="absolute top-4 left-4 right-4 z-10 flex items-center gap-3"><div class="flex gap-2 flex-1 max-w-md"><input type="text" placeholder="Center graph on..."${attr("value", searchQuery)} class="flex-1 px-3 py-2 bg-abyss/80 backdrop-blur-sm border border-subtle/30 rounded-lg text-text text-sm placeholder:text-muted focus:outline-none focus:border-synapse/50 transition"/> <button class="px-3 py-2 bg-synapse/20 border border-synapse/40 text-synapse-glow text-sm rounded-lg hover:bg-synapse/30 transition backdrop-blur-sm">Focus</button></div> <div class="flex gap-2 ml-auto">`);
|
||||
$$renderer2.select(
|
||||
{
|
||||
value: maxNodes,
|
||||
onchange: () => loadGraph(),
|
||||
class: "px-2 py-2 bg-abyss/80 backdrop-blur-sm border border-subtle/30 rounded-lg text-dim text-xs"
|
||||
},
|
||||
($$renderer3) => {
|
||||
$$renderer3.option({ value: 50 }, ($$renderer4) => {
|
||||
$$renderer4.push(`50 nodes`);
|
||||
});
|
||||
$$renderer3.option({ value: 100 }, ($$renderer4) => {
|
||||
$$renderer4.push(`100 nodes`);
|
||||
});
|
||||
$$renderer3.option({ value: 150 }, ($$renderer4) => {
|
||||
$$renderer4.push(`150 nodes`);
|
||||
});
|
||||
$$renderer3.option({ value: 200 }, ($$renderer4) => {
|
||||
$$renderer4.push(`200 nodes`);
|
||||
});
|
||||
}
|
||||
);
|
||||
$$renderer2.push(` <button${attr("disabled", isDreaming, true)}${attr_class(`px-4 py-2 rounded-lg bg-dream/20 border border-dream/40 text-dream-glow text-sm hover:bg-dream/30 transition-all backdrop-blur-sm disabled:opacity-50 ${stringify("")}`)}>${escape_html("◈ Dream")}</button> <button class="px-3 py-2 bg-abyss/80 backdrop-blur-sm border border-subtle/30 rounded-lg text-dim text-sm hover:text-text transition">↻</button></div></div> <div class="absolute bottom-4 left-4 z-10 text-xs text-dim backdrop-blur-sm bg-abyss/60 rounded-lg px-3 py-2 border border-subtle/20">`);
|
||||
if (graphData) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<span>${escape_html(graphData.nodeCount)} nodes</span> <span class="mx-2 text-subtle">·</span> <span>${escape_html(graphData.edgeCount)} edges</span> <span class="mx-2 text-subtle">·</span> <span>depth ${escape_html(graphData.depth)}</span>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> `);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
if ($$store_subs) unsubscribe_stores($$store_subs);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_page as default
|
||||
};
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
import { c as escape_html, e as ensure_array_like, b as attr_class, d as stringify } from "../../../../chunks/index.js";
|
||||
function _page($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let intentions = [];
|
||||
let predictions = [];
|
||||
let statusFilter = "active";
|
||||
$$renderer2.push(`<div class="p-6 max-w-5xl mx-auto space-y-8"><div class="flex items-center justify-between"><h1 class="text-xl text-bright font-semibold">Intentions & Predictions</h1> <span class="text-xs text-muted">${escape_html(intentions.length)} intentions</span></div> <div class="space-y-4"><div class="flex items-center gap-2"><h2 class="text-sm text-bright font-semibold">Prospective Memory</h2> <span class="text-xs text-muted">"Remember to do X when Y happens"</span></div> <div class="flex gap-1.5"><!--[-->`);
|
||||
const each_array = ensure_array_like(["active", "fulfilled", "snoozed", "cancelled", "all"]);
|
||||
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
|
||||
let status = each_array[$$index];
|
||||
$$renderer2.push(`<button${attr_class(`px-3 py-1.5 rounded-lg text-xs transition ${stringify(statusFilter === status ? "bg-synapse/20 text-synapse-glow border border-synapse/40" : "bg-surface/40 text-dim border border-subtle/20 hover:border-subtle/40")}`)}>${escape_html(status.charAt(0).toUpperCase() + status.slice(1))}</button>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> `);
|
||||
{
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<div class="space-y-2"><!--[-->`);
|
||||
const each_array_1 = ensure_array_like(Array(4));
|
||||
for (let $$index_1 = 0, $$length = each_array_1.length; $$index_1 < $$length; $$index_1++) {
|
||||
each_array_1[$$index_1];
|
||||
$$renderer2.push(`<div class="h-16 bg-surface/50 rounded-lg animate-pulse"></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> <div class="pt-6 border-t border-subtle/20 space-y-4"><div class="flex items-center gap-2"><h2 class="text-sm text-bright font-semibold">Predicted Needs</h2> <span class="text-xs text-muted">What you might need next</span></div> `);
|
||||
if (predictions.length === 0) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<div class="text-center py-8 text-dim"><div class="text-3xl mb-3 opacity-20">◬</div> <p class="text-sm">No predictions yet. Use Vestige more to train the predictive model.</p></div>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
$$renderer2.push(`<div class="space-y-2"><!--[-->`);
|
||||
const each_array_3 = ensure_array_like(predictions);
|
||||
for (let i = 0, $$length = each_array_3.length; i < $$length; i++) {
|
||||
let pred = each_array_3[i];
|
||||
$$renderer2.push(`<div class="p-3 bg-surface/40 border border-subtle/20 rounded-lg flex items-start gap-3"><div class="w-6 h-6 rounded-full bg-dream/20 text-dream-glow text-xs flex items-center justify-center flex-shrink-0 mt-0.5">${escape_html(i + 1)}</div> <div class="flex-1 min-w-0"><p class="text-sm text-text line-clamp-2">${escape_html(pred.content)}</p> <div class="flex gap-3 mt-1 text-xs text-muted"><span>${escape_html(pred.nodeType)}</span> `);
|
||||
if (pred.retention) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<span>${escape_html((Number(pred.retention) * 100).toFixed(0))}% retention</span>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--> `);
|
||||
if (pred.predictedNeed) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<span class="text-dream-glow">${escape_html(pred.predictedNeed)} need</span>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div></div></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div></div>`);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_page as default
|
||||
};
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
import { c as escape_html, a as attr, e as ensure_array_like, b as attr_class, d as stringify, ac as attr_style } from "../../../../chunks/index.js";
|
||||
import { a as api } from "../../../../chunks/api.js";
|
||||
import { N as NODE_TYPE_COLORS } from "../../../../chunks/index3.js";
|
||||
function _page($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let memories = [];
|
||||
let searchQuery = "";
|
||||
let selectedType = "";
|
||||
let selectedTag = "";
|
||||
let minRetention = 0;
|
||||
let loading = true;
|
||||
let selectedMemory = null;
|
||||
async function loadMemories() {
|
||||
loading = true;
|
||||
try {
|
||||
const params = {};
|
||||
if (searchQuery) ;
|
||||
if (selectedType) ;
|
||||
if (selectedTag) ;
|
||||
if (minRetention > 0) ;
|
||||
const res = await api.memories.list(params);
|
||||
memories = res.memories;
|
||||
} catch {
|
||||
memories = [];
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
function retentionColor(r) {
|
||||
if (r > 0.7) return "#10b981";
|
||||
if (r > 0.4) return "#f59e0b";
|
||||
return "#ef4444";
|
||||
}
|
||||
$$renderer2.push(`<div class="p-6 max-w-6xl mx-auto space-y-6"><div class="flex items-center justify-between"><h1 class="text-xl text-bright font-semibold">Memories</h1> <span class="text-dim text-sm">${escape_html(memories.length)} results</span></div> <div class="flex gap-3 flex-wrap"><input type="text" placeholder="Search memories..."${attr("value", searchQuery)} class="flex-1 min-w-64 px-4 py-2.5 bg-surface border border-subtle/40 rounded-lg text-text text-sm placeholder:text-muted focus:outline-none focus:border-synapse/60 focus:ring-1 focus:ring-synapse/30 transition"/> `);
|
||||
$$renderer2.select(
|
||||
{
|
||||
value: selectedType,
|
||||
onchange: loadMemories,
|
||||
class: "px-3 py-2.5 bg-surface border border-subtle/40 rounded-lg text-dim text-sm focus:outline-none"
|
||||
},
|
||||
($$renderer3) => {
|
||||
$$renderer3.option({ value: "" }, ($$renderer4) => {
|
||||
$$renderer4.push(`All types`);
|
||||
});
|
||||
$$renderer3.option({ value: "fact" }, ($$renderer4) => {
|
||||
$$renderer4.push(`Fact`);
|
||||
});
|
||||
$$renderer3.option({ value: "concept" }, ($$renderer4) => {
|
||||
$$renderer4.push(`Concept`);
|
||||
});
|
||||
$$renderer3.option({ value: "event" }, ($$renderer4) => {
|
||||
$$renderer4.push(`Event`);
|
||||
});
|
||||
$$renderer3.option({ value: "person" }, ($$renderer4) => {
|
||||
$$renderer4.push(`Person`);
|
||||
});
|
||||
$$renderer3.option({ value: "place" }, ($$renderer4) => {
|
||||
$$renderer4.push(`Place`);
|
||||
});
|
||||
$$renderer3.option({ value: "note" }, ($$renderer4) => {
|
||||
$$renderer4.push(`Note`);
|
||||
});
|
||||
$$renderer3.option({ value: "pattern" }, ($$renderer4) => {
|
||||
$$renderer4.push(`Pattern`);
|
||||
});
|
||||
$$renderer3.option({ value: "decision" }, ($$renderer4) => {
|
||||
$$renderer4.push(`Decision`);
|
||||
});
|
||||
}
|
||||
);
|
||||
$$renderer2.push(` <div class="flex items-center gap-2 text-xs text-dim"><span>Min retention:</span> <input type="range" min="0" max="1" step="0.1"${attr("value", minRetention)} class="w-24 accent-synapse"/> <span>${escape_html((minRetention * 100).toFixed(0))}%</span></div></div> `);
|
||||
if (loading) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<div class="grid gap-3"><!--[-->`);
|
||||
const each_array = ensure_array_like(Array(8));
|
||||
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
|
||||
each_array[$$index];
|
||||
$$renderer2.push(`<div class="h-24 bg-surface/50 rounded-lg animate-pulse"></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
$$renderer2.push(`<div class="grid gap-3"><!--[-->`);
|
||||
const each_array_1 = ensure_array_like(memories);
|
||||
for (let $$index_2 = 0, $$length = each_array_1.length; $$index_2 < $$length; $$index_2++) {
|
||||
let memory = each_array_1[$$index_2];
|
||||
$$renderer2.push(`<button${attr_class(`text-left p-4 bg-surface/50 border border-subtle/20 rounded-lg hover:border-synapse/30 hover:bg-surface transition-all duration-200 group ${stringify(selectedMemory?.id === memory.id ? "border-synapse/50 glow-synapse" : "")}`)}><div class="flex items-start justify-between gap-4"><div class="flex-1 min-w-0"><div class="flex items-center gap-2 mb-2"><span class="w-2 h-2 rounded-full"${attr_style(`background: ${stringify(NODE_TYPE_COLORS[memory.nodeType] || "#6b7280")}`)}></span> <span class="text-xs text-dim">${escape_html(memory.nodeType)}</span> <!--[-->`);
|
||||
const each_array_2 = ensure_array_like(memory.tags.slice(0, 3));
|
||||
for (let $$index_1 = 0, $$length2 = each_array_2.length; $$index_1 < $$length2; $$index_1++) {
|
||||
let tag = each_array_2[$$index_1];
|
||||
$$renderer2.push(`<span class="text-xs px-1.5 py-0.5 bg-deep rounded text-muted">${escape_html(tag)}</span>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> <p class="text-sm text-text leading-relaxed line-clamp-2">${escape_html(memory.content)}</p></div> <div class="flex flex-col items-end gap-1 flex-shrink-0"><div class="w-12 h-1.5 bg-deep rounded-full overflow-hidden"><div class="h-full rounded-full"${attr_style(`width: ${stringify(memory.retentionStrength * 100)}%; background: ${stringify(retentionColor(memory.retentionStrength))}`)}></div></div> <span class="text-xs text-muted">${escape_html((memory.retentionStrength * 100).toFixed(0))}%</span></div></div> `);
|
||||
if (selectedMemory?.id === memory.id) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<div class="mt-4 pt-4 border-t border-subtle/20 space-y-3"><p class="text-sm text-text whitespace-pre-wrap">${escape_html(memory.content)}</p> <div class="grid grid-cols-3 gap-3 text-xs text-dim"><div>Storage: ${escape_html((memory.storageStrength * 100).toFixed(1))}%</div> <div>Retrieval: ${escape_html((memory.retrievalStrength * 100).toFixed(1))}%</div> <div>Created: ${escape_html(new Date(memory.createdAt).toLocaleDateString())}</div></div> <div class="flex gap-2"><button class="px-3 py-1.5 bg-recall/20 text-recall text-xs rounded hover:bg-recall/30">Promote</button> <button class="px-3 py-1.5 bg-decay/20 text-decay text-xs rounded hover:bg-decay/30">Demote</button> <button class="px-3 py-1.5 bg-decay/10 text-decay/60 text-xs rounded hover:bg-decay/20 ml-auto">Delete</button></div></div>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></button>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_page as default
|
||||
};
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
import { c as escape_html, s as store_get, ac as attr_style, d as stringify, b as attr_class, a as attr, e as ensure_array_like, f as unsubscribe_stores } from "../../../../chunks/index.js";
|
||||
import { m as memoryCount, a as avgRetention, i as isConnected } from "../../../../chunks/websocket.js";
|
||||
function _page($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
var $$store_subs;
|
||||
let consolidating = false;
|
||||
let dreaming = false;
|
||||
$$renderer2.push(`<div class="p-6 max-w-4xl mx-auto space-y-8"><div class="flex items-center justify-between"><h1 class="text-xl text-bright font-semibold">Settings & System</h1> <button class="text-xs text-dim hover:text-text transition">Refresh</button></div> <div class="grid grid-cols-2 md:grid-cols-4 gap-3"><div class="p-4 bg-surface/30 border border-subtle/20 rounded-lg text-center"><div class="text-2xl text-bright font-bold">${escape_html(store_get($$store_subs ??= {}, "$memoryCount", memoryCount))}</div> <div class="text-xs text-dim mt-1">Memories</div></div> <div class="p-4 bg-surface/30 border border-subtle/20 rounded-lg text-center"><div class="text-2xl font-bold"${attr_style(`color: ${stringify(store_get($$store_subs ??= {}, "$avgRetention", avgRetention) > 0.7 ? "#10b981" : store_get($$store_subs ??= {}, "$avgRetention", avgRetention) > 0.4 ? "#f59e0b" : "#ef4444")}`)}>${escape_html((store_get($$store_subs ??= {}, "$avgRetention", avgRetention) * 100).toFixed(1))}%</div> <div class="text-xs text-dim mt-1">Avg Retention</div></div> <div class="p-4 bg-surface/30 border border-subtle/20 rounded-lg text-center"><div class="text-2xl text-bright font-bold flex items-center justify-center gap-2"><div${attr_class(`w-2.5 h-2.5 rounded-full ${stringify(store_get($$store_subs ??= {}, "$isConnected", isConnected) ? "bg-recall animate-pulse-glow" : "bg-decay")}`)}></div> <span class="text-sm">${escape_html(store_get($$store_subs ??= {}, "$isConnected", isConnected) ? "Online" : "Offline")}</span></div> <div class="text-xs text-dim mt-1">WebSocket</div></div> <div class="p-4 bg-surface/30 border border-subtle/20 rounded-lg text-center"><div class="text-2xl text-synapse-glow font-bold">v2.0</div> <div class="text-xs text-dim mt-1">Vestige</div></div></div> <section class="space-y-4"><h2 class="text-sm text-bright font-semibold flex items-center gap-2"><span class="text-dream">◈</span> Cognitive Operations</h2> <div class="p-4 bg-surface/30 border border-subtle/20 rounded-lg space-y-3"><div class="flex items-center justify-between"><div><div class="text-sm text-text font-medium">FSRS-6 Consolidation</div> <div class="text-xs text-dim">Apply spaced-repetition decay, regenerate embeddings, run maintenance</div></div> <button${attr("disabled", consolidating, true)} class="px-4 py-2 bg-warning/20 border border-warning/40 text-warning text-sm rounded-lg hover:bg-warning/30 transition disabled:opacity-50 flex items-center gap-2">`);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
$$renderer2.push(`Consolidate`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></button></div> `);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> <div class="p-4 bg-surface/30 border border-subtle/20 rounded-lg space-y-3"><div class="flex items-center justify-between"><div><div class="text-sm text-text font-medium">Memory Dream Cycle</div> <div class="text-xs text-dim">Replay memories, discover hidden connections, synthesize insights</div></div> <button${attr("disabled", dreaming, true)}${attr_class(`px-4 py-2 bg-dream/20 border border-dream/40 text-dream-glow text-sm rounded-lg hover:bg-dream/30 transition disabled:opacity-50 flex items-center gap-2 ${stringify("")}`)}>`);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
$$renderer2.push(`Dream`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></button></div> `);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div></section> `);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--> <section class="space-y-4"><h2 class="text-sm text-bright font-semibold flex items-center gap-2"><span class="text-synapse">⌨</span> Keyboard Shortcuts</h2> <div class="p-4 bg-surface/30 border border-subtle/20 rounded-lg"><div class="grid grid-cols-2 gap-2 text-xs"><!--[-->`);
|
||||
const each_array_2 = ensure_array_like([
|
||||
{ key: "⌘ K", desc: "Command palette" },
|
||||
{ key: "/", desc: "Focus search" },
|
||||
{ key: "G", desc: "Go to Graph" },
|
||||
{ key: "M", desc: "Go to Memories" },
|
||||
{ key: "T", desc: "Go to Timeline" },
|
||||
{ key: "F", desc: "Go to Feed" },
|
||||
{ key: "E", desc: "Go to Explore" },
|
||||
{ key: "S", desc: "Go to Stats" }
|
||||
]);
|
||||
for (let $$index_2 = 0, $$length = each_array_2.length; $$index_2 < $$length; $$index_2++) {
|
||||
let shortcut = each_array_2[$$index_2];
|
||||
$$renderer2.push(`<div class="flex items-center gap-2 py-1"><kbd class="px-1.5 py-0.5 bg-deep rounded text-[10px] font-mono text-muted min-w-[2rem] text-center">${escape_html(shortcut.key)}</kbd> <span class="text-dim">${escape_html(shortcut.desc)}</span></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div></div></section> <section class="space-y-4"><h2 class="text-sm text-bright font-semibold flex items-center gap-2"><span class="text-memory">◎</span> About</h2> <div class="p-4 bg-surface/30 border border-subtle/20 rounded-lg space-y-3"><div class="flex items-center gap-4"><div class="w-12 h-12 rounded-xl bg-gradient-to-br from-dream to-synapse flex items-center justify-center text-bright text-xl font-bold shadow-lg shadow-synapse/20">V</div> <div><div class="text-sm text-bright font-semibold">Vestige v2.0 "Cognitive Leap"</div> <div class="text-xs text-dim">Your AI's long-term memory system</div></div></div> <div class="grid grid-cols-2 gap-2 text-xs text-dim pt-2 border-t border-subtle/10"><div>29 cognitive modules</div> <div>FSRS-6 spaced repetition</div> <div>Nomic Embed v1.5 (256d)</div> <div>Jina Reranker v1 Turbo</div> <div>USearch HNSW (20x FAISS)</div> <div>Local-first, zero cloud</div></div> <div class="text-[10px] text-muted pt-1">Built with Rust + Axum + SvelteKit 2 + Svelte 5 + Three.js + Tailwind CSS 4</div></div></section></div>`);
|
||||
if ($$store_subs) unsubscribe_stores($$store_subs);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_page as default
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { e as ensure_array_like } from "../../../../chunks/index.js";
|
||||
function _page($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
$$renderer2.push(`<div class="p-6 max-w-5xl mx-auto space-y-6"><h1 class="text-xl text-bright font-semibold">System Stats</h1> `);
|
||||
{
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<div class="grid grid-cols-2 lg:grid-cols-4 gap-4"><!--[-->`);
|
||||
const each_array = ensure_array_like(Array(8));
|
||||
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
|
||||
each_array[$$index];
|
||||
$$renderer2.push(`<div class="h-24 bg-surface/50 rounded-lg animate-pulse"></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_page as default
|
||||
};
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import { e as ensure_array_like, c as escape_html, ac as attr_style, d as stringify } from "../../../../chunks/index.js";
|
||||
import { a as api } from "../../../../chunks/api.js";
|
||||
import { N as NODE_TYPE_COLORS } from "../../../../chunks/index3.js";
|
||||
function _page($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let timeline = [];
|
||||
let loading = true;
|
||||
let days = 14;
|
||||
let expandedDay = null;
|
||||
async function loadTimeline() {
|
||||
loading = true;
|
||||
try {
|
||||
const res = await api.timeline(days, 500);
|
||||
timeline = res.timeline;
|
||||
} catch {
|
||||
timeline = [];
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
$$renderer2.push(`<div class="p-6 max-w-4xl mx-auto space-y-6"><div class="flex items-center justify-between"><h1 class="text-xl text-bright font-semibold">Timeline</h1> `);
|
||||
$$renderer2.select(
|
||||
{
|
||||
value: days,
|
||||
onchange: loadTimeline,
|
||||
class: "px-3 py-2 bg-surface border border-subtle/40 rounded-lg text-dim text-sm"
|
||||
},
|
||||
($$renderer3) => {
|
||||
$$renderer3.option({ value: 7 }, ($$renderer4) => {
|
||||
$$renderer4.push(`7 days`);
|
||||
});
|
||||
$$renderer3.option({ value: 14 }, ($$renderer4) => {
|
||||
$$renderer4.push(`14 days`);
|
||||
});
|
||||
$$renderer3.option({ value: 30 }, ($$renderer4) => {
|
||||
$$renderer4.push(`30 days`);
|
||||
});
|
||||
$$renderer3.option({ value: 90 }, ($$renderer4) => {
|
||||
$$renderer4.push(`90 days`);
|
||||
});
|
||||
}
|
||||
);
|
||||
$$renderer2.push(`</div> `);
|
||||
if (loading) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<div class="space-y-4"><!--[-->`);
|
||||
const each_array = ensure_array_like(Array(7));
|
||||
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
|
||||
each_array[$$index];
|
||||
$$renderer2.push(`<div class="h-16 bg-surface/50 rounded-lg animate-pulse"></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
} else if (timeline.length === 0) {
|
||||
$$renderer2.push("<!--[1-->");
|
||||
$$renderer2.push(`<div class="text-center py-20 text-dim"><p>No memories in the selected time range.</p></div>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
$$renderer2.push(`<div class="relative"><div class="absolute left-6 top-0 bottom-0 w-px bg-subtle/30"></div> <div class="space-y-4"><!--[-->`);
|
||||
const each_array_1 = ensure_array_like(timeline);
|
||||
for (let $$index_3 = 0, $$length = each_array_1.length; $$index_3 < $$length; $$index_3++) {
|
||||
let day = each_array_1[$$index_3];
|
||||
$$renderer2.push(`<div class="relative pl-14"><div class="absolute left-4 top-3 w-5 h-5 rounded-full border-2 border-synapse bg-abyss flex items-center justify-center"><div class="w-2 h-2 rounded-full bg-synapse"></div></div> <button class="w-full text-left p-4 bg-surface/40 border border-subtle/20 rounded-lg hover:border-synapse/30 transition-all"><div class="flex items-center justify-between"><div><span class="text-sm text-bright font-medium">${escape_html(day.date)}</span> <span class="text-xs text-dim ml-2">${escape_html(day.count)} memories</span></div> <div class="flex gap-1"><!--[-->`);
|
||||
const each_array_2 = ensure_array_like(day.memories.slice(0, 10));
|
||||
for (let $$index_1 = 0, $$length2 = each_array_2.length; $$index_1 < $$length2; $$index_1++) {
|
||||
let m = each_array_2[$$index_1];
|
||||
$$renderer2.push(`<div class="w-2 h-2 rounded-full"${attr_style(`background: ${stringify(NODE_TYPE_COLORS[m.nodeType] || "#6b7280")}; opacity: ${stringify(0.3 + m.retentionStrength * 0.7)}`)}></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--> `);
|
||||
if (day.memories.length > 10) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<span class="text-xs text-muted">+${escape_html(day.memories.length - 10)}</span>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div></div> `);
|
||||
if (expandedDay === day.date) {
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<div class="mt-3 pt-3 border-t border-subtle/20 space-y-2"><!--[-->`);
|
||||
const each_array_3 = ensure_array_like(day.memories);
|
||||
for (let $$index_2 = 0, $$length2 = each_array_3.length; $$index_2 < $$length2; $$index_2++) {
|
||||
let m = each_array_3[$$index_2];
|
||||
$$renderer2.push(`<div class="flex items-start gap-2 text-sm"><div class="w-2 h-2 mt-1.5 rounded-full flex-shrink-0"${attr_style(`background: ${stringify(NODE_TYPE_COLORS[m.nodeType] || "#6b7280")}`)}></div> <div class="flex-1 min-w-0"><span class="text-dim line-clamp-1">${escape_html(m.content)}</span></div> <span class="text-xs text-muted flex-shrink-0">${escape_html((m.retentionStrength * 100).toFixed(0))}%</span></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
} else {
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></button></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_page as default
|
||||
};
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import { g as getContext, e as ensure_array_like, s as store_get, a as attr, b as attr_class, c as escape_html, d as stringify, f as unsubscribe_stores } from "../../chunks/index.js";
|
||||
import "@sveltejs/kit/internal";
|
||||
import "../../chunks/exports.js";
|
||||
import "../../chunks/utils2.js";
|
||||
import "@sveltejs/kit/internal/server";
|
||||
import "../../chunks/root.js";
|
||||
import "../../chunks/state.svelte.js";
|
||||
import { b as base } from "../../chunks/server.js";
|
||||
import { i as isConnected, m as memoryCount, a as avgRetention } from "../../chunks/websocket.js";
|
||||
const getStores = () => {
|
||||
const stores$1 = getContext("__svelte__");
|
||||
return {
|
||||
/** @type {typeof page} */
|
||||
page: {
|
||||
subscribe: stores$1.page.subscribe
|
||||
},
|
||||
/** @type {typeof navigating} */
|
||||
navigating: {
|
||||
subscribe: stores$1.navigating.subscribe
|
||||
},
|
||||
/** @type {typeof updated} */
|
||||
updated: stores$1.updated
|
||||
};
|
||||
};
|
||||
const page = {
|
||||
subscribe(fn) {
|
||||
const store = getStores().page;
|
||||
return store.subscribe(fn);
|
||||
}
|
||||
};
|
||||
function _layout($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
var $$store_subs;
|
||||
let { children } = $$props;
|
||||
const nav = [
|
||||
{ href: "/", label: "Graph", icon: "◎", shortcut: "G" },
|
||||
{
|
||||
href: "/memories",
|
||||
label: "Memories",
|
||||
icon: "◈",
|
||||
shortcut: "M"
|
||||
},
|
||||
{
|
||||
href: "/timeline",
|
||||
label: "Timeline",
|
||||
icon: "◷",
|
||||
shortcut: "T"
|
||||
},
|
||||
{ href: "/feed", label: "Feed", icon: "◉", shortcut: "F" },
|
||||
{ href: "/explore", label: "Explore", icon: "◬", shortcut: "E" },
|
||||
{
|
||||
href: "/intentions",
|
||||
label: "Intentions",
|
||||
icon: "◇",
|
||||
shortcut: "I"
|
||||
},
|
||||
{ href: "/stats", label: "Stats", icon: "◫", shortcut: "S" },
|
||||
{
|
||||
href: "/settings",
|
||||
label: "Settings",
|
||||
icon: "⚙",
|
||||
shortcut: ","
|
||||
}
|
||||
];
|
||||
const mobileNav = nav.slice(0, 5);
|
||||
function isActive(href, currentPath) {
|
||||
const path = currentPath.startsWith(base) ? currentPath.slice(base.length) || "/" : currentPath;
|
||||
if (href === "/") return path === "/" || path === "/graph";
|
||||
return path.startsWith(href);
|
||||
}
|
||||
$$renderer2.push(`<div class="flex flex-col md:flex-row h-screen overflow-hidden bg-void"><nav class="hidden md:flex w-16 lg:w-56 flex-shrink-0 bg-abyss border-r border-subtle/30 flex-col"><a href="/" class="flex items-center gap-3 px-4 py-5 border-b border-subtle/20"><div class="w-8 h-8 rounded-lg bg-gradient-to-br from-dream to-synapse flex items-center justify-center text-bright text-sm font-bold">V</div> <span class="hidden lg:block text-sm font-semibold text-bright tracking-wide">VESTIGE</span></a> <div class="flex-1 py-3 flex flex-col gap-1 px-2"><!--[-->`);
|
||||
const each_array = ensure_array_like(nav);
|
||||
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
|
||||
let item = each_array[$$index];
|
||||
const active = isActive(item.href, store_get($$store_subs ??= {}, "$page", page).url.pathname);
|
||||
$$renderer2.push(`<a${attr("href", item.href)}${attr_class(`flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 text-sm ${stringify(active ? "bg-synapse/15 text-synapse-glow border border-synapse/30 shadow-[0_0_12px_rgba(99,102,241,0.15)]" : "text-dim hover:text-text hover:bg-surface border border-transparent")}`)}><span class="text-base w-5 text-center">${escape_html(item.icon)}</span> <span class="hidden lg:block">${escape_html(item.label)}</span> <span class="hidden lg:block ml-auto text-[10px] text-muted/50 font-mono">${escape_html(item.shortcut)}</span></a>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> <div class="px-2 pb-2"><button class="w-full flex items-center gap-2 px-3 py-2 rounded-lg text-xs text-muted hover:text-dim hover:bg-surface/50 transition border border-subtle/20"><span class="text-[10px] font-mono bg-surface/60 px-1.5 py-0.5 rounded">⌘K</span> <span class="hidden lg:block">Command</span></button></div> <div class="px-3 py-4 border-t border-subtle/20 space-y-2"><div class="flex items-center gap-2 text-xs"><div${attr_class(`w-2 h-2 rounded-full ${stringify(store_get($$store_subs ??= {}, "$isConnected", isConnected) ? "bg-recall animate-pulse-glow" : "bg-decay")}`)}></div> <span class="hidden lg:block text-dim">${escape_html(store_get($$store_subs ??= {}, "$isConnected", isConnected) ? "Connected" : "Offline")}</span></div> <div class="hidden lg:block text-xs text-muted"><div>${escape_html(store_get($$store_subs ??= {}, "$memoryCount", memoryCount))} memories</div> <div>${escape_html((store_get($$store_subs ??= {}, "$avgRetention", avgRetention) * 100).toFixed(0))}% retention</div></div></div></nav> <main class="flex-1 overflow-y-auto pb-16 md:pb-0"><div class="animate-page-in svelte-12qhfyh">`);
|
||||
children($$renderer2);
|
||||
$$renderer2.push(`<!----></div></main> <nav class="md:hidden fixed bottom-0 inset-x-0 bg-abyss/95 backdrop-blur-xl border-t border-subtle/30 z-40 safe-bottom svelte-12qhfyh"><div class="flex items-center justify-around px-2 py-1"><!--[-->`);
|
||||
const each_array_1 = ensure_array_like(mobileNav);
|
||||
for (let $$index_1 = 0, $$length = each_array_1.length; $$index_1 < $$length; $$index_1++) {
|
||||
let item = each_array_1[$$index_1];
|
||||
const active = isActive(item.href, store_get($$store_subs ??= {}, "$page", page).url.pathname);
|
||||
$$renderer2.push(`<a${attr("href", item.href)}${attr_class(`flex flex-col items-center gap-0.5 px-3 py-2 rounded-lg transition-all min-w-[3.5rem] ${stringify(active ? "text-synapse-glow" : "text-muted")}`)}><span class="text-lg">${escape_html(item.icon)}</span> <span class="text-[9px]">${escape_html(item.label)}</span></a>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--> <button class="flex flex-col items-center gap-0.5 px-3 py-2 rounded-lg text-muted min-w-[3.5rem]"><span class="text-lg">⋯</span> <span class="text-[9px]">More</span></button></div></nav></div> `);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]-->`);
|
||||
if ($$store_subs) unsubscribe_stores($$store_subs);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_layout as default
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import { a as attr, b as attr_class, c as escape_html, d as stringify } from "../../chunks/index.js";
|
||||
import "../../chunks/websocket.js";
|
||||
function _page($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let isDreaming = false;
|
||||
$$renderer2.push(`<div class="h-full relative">`);
|
||||
{
|
||||
$$renderer2.push("<!--[-->");
|
||||
$$renderer2.push(`<div class="h-full flex items-center justify-center"><div class="text-center space-y-4"><div class="w-16 h-16 mx-auto rounded-full border-2 border-synapse/30 border-t-synapse animate-spin"></div> <p class="text-dim text-sm">Loading memory graph...</p></div></div>`);
|
||||
}
|
||||
$$renderer2.push(`<!--]--> <div class="absolute top-4 left-4 flex gap-2 z-10"><button${attr("disabled", isDreaming, true)}${attr_class(`px-4 py-2 rounded-lg bg-dream/20 border border-dream/40 text-dream-glow text-sm hover:bg-dream/30 transition-all disabled:opacity-50 backdrop-blur-sm ${stringify("")}`)}>${escape_html("◎ Dream")}</button></div> <div class="absolute top-4 right-4 z-10 text-xs text-dim backdrop-blur-sm bg-abyss/60 rounded-lg px-3 py-2 border border-subtle/20">`);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div> `);
|
||||
{
|
||||
$$renderer2.push("<!--[!-->");
|
||||
}
|
||||
$$renderer2.push(`<!--]--></div>`);
|
||||
});
|
||||
}
|
||||
export {
|
||||
_page as default
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue