Space invites: Convert both username-add and email-invite (existing user)
paths from direct-add to invite flow — creates space_invite via EncryptID,
sends invite email with Accept button, dispatches space_invite notification
with Accept/Decline buttons in the notification bell. No one gets forcefully
added to a space anymore.
rSocials content linking: All generated campaign content now links through
to actual editable content. Draft post cards in thread gallery are clickable
(thread editor or campaign view). Campaign manager post cards expand on click
and thread badges link to thread editor. Wizard success screen shows
individual thread links. CampaignPost schema gains threadId field, stored on
commit so posts maintain their thread association.
Also includes canvas social media tools, social shape components
(folk-social-thread, folk-social-campaign, folk-social-newsletter),
and MI context-aware suggestion registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
One-shot migration to fix visibility for spaces that were changed
by stale client sync. Also imports updateSpaceMeta in index.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Automerge CRDT sync could overwrite space visibility when a client
with a stale cached doc reconnects and merges. Now the server
snapshots visibility and ownerDID before processing sync messages
and reverts any client-side changes to these fields.
These fields can only be changed through the authenticated API
(PATCH /api/spaces/:slug), not through CRDT sync.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ?v=4 to all SW registration URLs to bypass stale CF CDN cache
- Set Cache-Control: no-cache for sw.js and manifest.json so future
SW updates are never blocked by CDN caching
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cloudflare was caching sw.js for 4 hours (default JS caching),
preventing service worker updates from reaching clients.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- KiCad, FreeCAD, Blender, Scribus: add .wrapper flex container with
height:100% + min-height:0 so content stays within element bounds
- KiCad assembler: regex fallback for non-JSON tool results (SVG, Gerber, PDF)
- Scribus image gen: actually write downloaded fal.ai images to disk
(was creating imagePath but never saving bytes)
- Mount rspace-files volume in scribus-novnc so generated images are
accessible from both containers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Blender: add wrapper with height:100%, min-height:0 for flex shrink,
object-fit:contain on img — render stays within shape bounds.
FreeCAD: update assembleFreecadResult to scan all tool results for file
paths (.step, .stl, .png), not just execute_python_script JSON parsing.
Add preview PNG rendering instruction to system prompt. Add subdirectory
file serving routes for /data/files/generated/:subdir/:filename. Add
STEP/STL/SVG/PDF mime types.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MI now loads space doc to filter module list, capabilities, and fallback
by enabledModules. Canvas fetches /api/modules and space modules in
parallel via Promise.all, calling setModules once with filtered list.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
EEVEE needs GPU; Cycles CPU works headless. Added libegl1, libgl1-mesa-dri,
libglx-mesa0 to Dockerfile. Updated Gemini prompt to specify Cycles engine
with 64 samples.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a module script (e.g. canvas-*.js) fails to load (502 during
deploy, network error), the pane stayed in cache with a blank canvas.
Subsequent tab switches showed the broken cached pane instead of
re-fetching. Now script onerror removes the failed tag and evicts
the pane, so the next switchTo does a fresh fetch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract autoShowIfFirstVisit() so it runs both on initial page load
and on SPA tab switches. Uses localStorage rapp_info_seen_{moduleId}
to ensure each rApp's landing popup shows exactly once.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SSE transport crashes on concurrent connections (supergateway
single-session limit). StreamableHTTP supports multiple sessions.
Also set KICAD_PYTHON=/usr/bin/python3 for existsSync validation
and install missing requests package.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Server now relays presence-leave alongside presence messages for immediate peer removal
- Overlay properly unsubscribes leave listener on disconnectedCallback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Register rDesign in folk-rapp MODULE_META and shell FAVICON_BADGE_MAP
- Handle explicit presence-leave messages for immediate peer cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Mobile toolbar collapsed position now flush with bottom-toolbar (bottom: 8px)
- Toolbar defaults to collapsed on mobile (<768px)
- Zoom expand/minimize uses distinct icons (magnifier +/-) instead of CSS rotation
- SW update banner on all pages: "New version available — Tap to update"
- Detects controllerchange + updatefound events
- Purple gradient bar, dismissible, reloads on tap
- Added to both shell.ts (module pages) and canvas.html (standalone)
- folk-rapp: filter picker/switcher by enabled modules
- server/shell: react to modules-changed event for runtime module toggling
- collab-presence: minor overlay updates
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch from broken StdioClientTransport (child process) to
SSEClientTransport (HTTP to sidecar containers via supergateway).
Both sidecars share rspace-files volume so generated CAD files
(STEP, STL, Gerber, SVG) are directly servable without copying.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
qwen2.5:14b doesn't exist on the server, causing silent 404 from
Ollama and 502 to the client. Also added error logging for non-ok
Ollama responses.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix invite accept fetch URL in shell.ts (was missing /api/spaces prefix)
- After accepting invite, redirect to the invited space instead of reloading
- Notification actionUrls now point to the space subdomain (https://slug.rspace.online)
- Direct-add email includes inviter name, role, and space description
- Identity invite email includes space name/role context when inviting to a space
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
RunPod was hard-gated — returned 503 when RUNPOD_API_KEY missing,
blocking even LLM script generation. Now generates script via Ollama
regardless, only attempts RunPod render if key is configured. Health
check returns warnings (non-blocking) vs issues (blocking). Default
model switched to qwen2.5:14b (available on server). Regex also
handles non-python-tagged code blocks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Space Settings section in dropdown with visibility (public/permissioned/private)
and description fields, matching the full edit space modal
- GET /api/spaces/:slug now includes description field
- listSpaceInvites merges both space_invites and identity_invites tables
so email invites appear in Pending Invites
- revokeSpaceInvite falls through to identity_invites table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increase .rapp-subnav top from 92px to 93px so pill buttons
don't clip under the fixed header + tab-row border.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Abort previous in-flight fetch when switchTo() is called again, and
guard the shell's fallback navigation against stale callbacks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix server-side redirect to always use canonical rspace.online as base
domain instead of deriving from hostClean (prevents demo.rspace.rspace.online)
- Fix bare-domain check to exact match instead of .includes() (prevents
stacked subdomains from triggering bare-domain routing)
- Fix client-side rspaceNavUrl to guard against reserved subdomain names
being used as space subdomains (e.g. rspace.rspace.online)
- Fix identity component _navUrl with same canonical domain guards
- Remove "Try Demo" header button from all shell rendering functions
- Remove demo-btn CSS styles
- Fix pre-existing SchemaType error in Gemini tool declarations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Transform MI from single-shot chat into an agentic system:
- LiteLLM provider with Claude Sonnet/Haiku models via proxy
- Agentic loop (max 5 turns): stream → parse actions → execute server-side → feed results back
- Server-side media generation (fal.ai + Gemini) as first-class MI actions
- Module data queries (rnotes, rtasks, rcal) read directly from Automerge
- System prompt enriched with recent notes, open tasks, and calendar events
- Client handles new NDJSON types (turn, action-start, action-result)
- Extracted shared media helpers, refactored image/video endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The IIFE raced with doc loading so listCommunities returned empty.
Moved into the .then() callback to ensure all docs are loaded first.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On subdomain routing (e.g. demo.rspace.online), the space slug belongs
only in the subdomain — never in the URL path. This fixes all server
and client code that was generating /{space}/module paths on subdomains.
Server fixes:
- index.ts: notification actionUrls, template/disabled-module redirects,
subdomain passthrough (now redirects HTML, rewrites API), WS notifications
- output-list.ts: subdomain-aware path prefix for hrefs and fetch URLs
- shell.ts: dashboard pushState URL
Client fixes (basePath getter pattern):
- folk-book-shelf.ts, folk-splat-viewer.ts: _basePath getter
- folk-campaign-wizard.ts: basePath subdomain check
- folk-trips-planner.ts: use __rspaceNavUrl for canvas export
- rschedule/landing.ts: onclick handlers use __rspaceNavUrl
- rsplat/mod.ts: legacy view redirect subdomain check
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Provision {space}@rspace.online forwarding aliases that route to
opted-in members' personal emails. Admins/mods opted in by default;
regular members can opt in via PUT /api/spaces/:slug/email-forwarding/me.
New: space-alias-service.ts, schema tables, 8 DB functions, 6 API routes.
Hooks: rinbox onSpaceCreate/Delete, spaces.ts member lifecycle, startup migration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add bidirectional sync between rTasks and ClickUp:
- API client with 100 req/min rate limiter
- OAuth2 + personal API token connection flows
- Import wizard (workspace → space → list picker)
- Outbound push queue (5s intervals, 10-item batches)
- Inbound webhook with HMAC-SHA256 validation
- Field-level conflict detection (rTasks wins)
- Source badges (purple CU) with sync status dots on task cards
- Sync status indicator in board header for connected boards
Also fix 6 pre-existing TS errors across crowdsurf, rcal, rnotes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds diagnostic console.log to layer-switch handler, TabCache.switchTo,
fetchAndInject, and reconcileRemoteLayers to identify why clicking the
rspace tab closes all tabs and shows the dashboard.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
reconcileRemoteLayers() could wipe all local tabs when Automerge sync
or BroadcastChannel delivered empty layer data (CRDT initial state,
sync race). This caused clicking tabs to show an infinite-loading
dashboard. Now: empty remote layers are rejected when an active module
exists, and the current module always stays in the tab list.
Also adds 10s fetch timeout to TabCache.fetchAndInject() to prevent
infinite loading spinners on slow/failed module fetches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The access gate and space dashboard redirect scripts checked only
localStorage, which is per-origin. When navigating between subdomains
(e.g. demo → jeff), the session wasn't found. Now both scripts also
check the eid_token cross-subdomain cookie and sync it to localStorage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Gemini Flash agentic loop that converts natural language prompts
into real MCP tool call sequences for PCB design (KiCad) and parametric
CAD (FreeCAD). Dynamic schema conversion from MCP tools to Gemini
function declarations, 8-turn/60s loop with real execution and result
feedback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Automerge docs created before the tags schema don't have the field.
The migration runs 5s after startup (after loadAllDocs completes),
patches missing tags onto events, and assigns known demo event tags.
Also removes debug endpoint and tracing logs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 1: MI now knows the current date/time and upcoming events (14-day
lookahead, 5 events max) via direct Automerge read — no HTTP overhead.
Phase 2: Tags (string[] | null) on CalendarEvent for first-class filtering.
Saved views (named filter presets) with full CRUD API. Tag filter on
GET /api/events via comma-separated AND logic. Demo events seeded with tags.
Phase 3: Calendar MCP server (5 tools: cal_list_events, cal_get_event,
cal_list_sources, cal_list_views, cal_create_event) registered in .mcp.json.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The demo Automerge doc had visibility: "private" from initial creation.
ensureDemoCommunity now forces visibility to "public" on every startup
if it drifted.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Add GET /rvote/api/* to public endpoint whitelist so proposal
listings work on private/permissioned spaces without auth.
2. Campaign wizard now checks for auth token before POSTing,
showing "Please sign in" instead of a cryptic 401.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The sub-path middleware (/:space/:moduleId/*) already blocked disabled
modules, but the root path (/:space/:moduleId) didn't. Now both paths
consistently check enabledModules before allowing access.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two fixes:
1. Bare-domain routing used url.protocol (always http: behind TLS
termination) for redirects, causing mixed-content blocks. Added
proto helper that uses https: on production domains. Also rewrite
/{space}/api/... calls internally instead of redirecting to the
subdomain.
2. rDesign SSE stream reader now catches QUIC protocol errors on
stream close gracefully.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Non-demo space dashboards now redirect logged-out visitors to
rspace.online/ instead of showing another user's rApp grid. Private
space module pages redirect to rspace.online/{moduleId} instead of
showing the sign-in gate overlay.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After logout, reload the page so the server re-renders the current rApp
in logged-out/demo mode instead of showing a blank screen. Cross-tab
logout also triggers a reload. Space dashboard now redirects logged-in
users to the rSpace canvas instead of showing the rApp grid.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changed syncTabsFromServer to replace local tabs with server tabs
instead of merging (union). This prevents tabs closed in browser A
from being resurrected when browser B refreshes. Also added server
sync to the iframe module landing path which was localStorage-only.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The demo space auth middleware was blocking POST requests with 403.
Add /rdesign/api/ to isPublicEndpoint list, matching rwallet pattern.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The "N online" collab badge was position:fixed at top:8px, overlapping
the header login area. Move it into the tab bar slot (main shell) or
header-right section (standalone shells) so it flows inline with other
chrome elements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Balance queries, Safe detection, and chain analysis are blockchain
reads that should work for any authenticated user regardless of
space membership. The route handlers enforce their own auth.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the global "Your Spaces" grid with a space-centric dashboard showing
members, previously open tools, recent activity, active votes, and quick
actions. Fix layout cut-off by positioning dashboard fixed below header+tab
row (top: 92px) with sidebar-push support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>