Compare commits

...

2 Commits

Author SHA1 Message Date
Jeff Emmett f29cf02fb7 Merge branch 'dev'
CI/CD / deploy (push) Failing after 1m57s Details
2026-04-16 17:18:24 -04:00
Jeff Emmett 3a614e2866 rename: finish rschedule → rminders migration
Complete the rename started in dda7760 (which removed rschedule/ but
left callers unmigrated and the rminders/ dir uncommitted). Updates
vite.config.ts build entries, API base fetches in folk-comment-pin,
folk-rapp widget map, module-display meta, calendar reminder-drop
route, docs comment-panel, e2e fixtures, shell/landing/mcp-server
references, and backlog/ONTOLOGY docs.

Fixes vite build failure: "Could not resolve entry module
modules/rschedule/components/folk-schedule-app.ts".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 17:18:17 -04:00
30 changed files with 77 additions and 75 deletions

View File

@ -265,7 +265,8 @@ redirects to the unified server with subdomain-based space routing.
| **rMaps** | rmaps.online | Geographic mapping & location hierarchy |
| **rTrips** | rtrips.online | Trip planning with itineraries |
| **rTasks** | rtasks.online | Task boards & project management |
| **rSchedule** | rschedule.online | Persistent cron-based job scheduling with email, webhooks & briefings |
| **rMinders** | rminders.online | Reminders, cron jobs, and automation workflows — email, webhooks, briefings |
| **rSchedule** | rschedule.online | Calendly-style booking from rCal availability (native port of schedule-jeffemmett) |
### Communication

View File

@ -56,7 +56,8 @@ These are the building blocks that all rApps share and compose:
| **rMaps** | Real-time location sharing with OSM tiles, indoor routing (c3nav), privacy controls (precision fuzzing, ghost mode), and push notifications |
| **rTrips** | Collaborative trip planner with itinerary, routing, expenses, and packing lists |
| **rTasks** | Kanban boards with ClickUp bi-directional sync |
| **rSchedule** | Cron-based job scheduling — emails, webhooks, calendar events, broadcasts, workflow nodes |
| **rMinders** | Reminders, cron jobs, automation workflows — emails, webhooks, calendar events, broadcasts |
| **rSchedule** | Calendly-style public booking against rCal availability |
### Communication

View File

@ -1,19 +1,19 @@
---
id: TASK-104
title: n8n-style automation canvas for rSchedule
title: n8n-style automation canvas for rMinders
status: Done
assignee: []
created_date: '2026-03-10 18:43'
labels:
- rschedule
- rminders
- feature
- automation
dependencies: []
references:
- modules/rschedule/schemas.ts
- modules/rschedule/mod.ts
- modules/rschedule/components/folk-automation-canvas.ts
- modules/rschedule/components/automation-canvas.css
- modules/rminders/schemas.ts
- modules/rminders/mod.ts
- modules/rminders/components/folk-automation-canvas.ts
- modules/rminders/components/automation-canvas.css
- vite.config.ts
priority: medium
---
@ -21,14 +21,14 @@ priority: medium
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
Visual workflow builder at /:space/rschedule/reminders that lets users wire together triggers, conditions, and actions from any rApp — enabling automations like "if my location approaches home, notify family" or "when document sign-off completes, schedule posts and notify comms director."
Visual workflow builder at /:space/rminders/reminders that lets users wire together triggers, conditions, and actions from any rApp — enabling automations like "if my location approaches home, notify family" or "when document sign-off completes, schedule posts and notify comms director."
Built with SVG canvas (pan/zoom/Bezier wiring), 15 node types across 3 categories, REST-persisted CRUD, topological execution engine, cron tick loop integration, and webhook trigger endpoint.
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Canvas loads at /:space/rschedule/reminders with node palette
- [ ] #1 Canvas loads at /:space/rminders/reminders with node palette
- [ ] #2 Drag nodes from palette, wire ports, configure — auto-saves via REST
- [ ] #3 Run All on manual-trigger workflow — nodes animate, execution log shows results
- [ ] #4 Cron workflows execute on tick loop
@ -39,9 +39,9 @@ Built with SVG canvas (pan/zoom/Bezier wiring), 15 node types across 3 categorie
## Final Summary
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
Implemented n8n-style automation canvas for rSchedule with 5 files (2490 lines added):
Implemented n8n-style automation canvas for rMinders with 5 files (2490 lines added):
**schemas.ts** — 15 automation node types (5 triggers, 4 conditions, 6 actions), NODE_CATALOG with typed ports and config schemas, Workflow/WorkflowNode/WorkflowEdge types, extended ScheduleDoc.
**schemas.ts** — 15 automation node types (5 triggers, 4 conditions, 6 actions), NODE_CATALOG with typed ports and config schemas, Workflow/WorkflowNode/WorkflowEdge types, extended MindersDoc.
**folk-automation-canvas.ts** — SVG canvas with pan/zoom, left sidebar node palette (drag-to-add), Bezier edge wiring between typed ports, right sidebar config panel driven by NODE_CATALOG, execution visualization, REST persistence with 1.5s debounced auto-save.

View File

@ -24,5 +24,5 @@ Created shared ViewHistory<V> utility class providing stack-based back navigatio
## Final Summary
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
Commit 31b0885 on dev+main. New shared/view-history.ts with ViewHistory<V> class (push/back/canGoBack/peekBack/reset, max depth 20). Integrated into rtrips, rmaps, rtasks, rforum, rphotos, rvote, rnotes, rinbox, rschedule, rcart. Full rWork→rTasks rename: directory modules/rwork→modules/rtasks, component folk-work-board→folk-tasks-board, class FolkWorkBoard→FolkTasksBoard, all cross-module refs, docker-compose, vite config, encryptid CORS, landing pages. Removed rwork.online from cloudflared config and deleted its Cloudflare zone.
Commit 31b0885 on dev+main. New shared/view-history.ts with ViewHistory<V> class (push/back/canGoBack/peekBack/reset, max depth 20). Integrated into rtrips, rmaps, rtasks, rforum, rphotos, rvote, rnotes, rinbox, rminders, rcart. Full rWork→rTasks rename: directory modules/rwork→modules/rtasks, component folk-work-board→folk-tasks-board, class FolkWorkBoard→FolkTasksBoard, all cross-module refs, docker-compose, vite config, encryptid CORS, landing pages. Removed rwork.online from cloudflared config and deleted its Cloudflare zone.
<!-- SECTION:FINAL_SUMMARY:END -->

View File

@ -24,7 +24,7 @@ Ensure every rApp module has:
## Current State (27 modules)
- **12 already have local-first/Automerge**: rbooks, rcal, rcart, rfiles, rflows, rinbox, rnotes, rsocials, rsplat, rtasks, rtrips, rvote
- **2 use ephemeral WebSocket sync** (no Automerge): rmaps, rnetwork
- **13 have NO real-time sync**: rchoices, rdata, rdesign, rdocs, rforum, rmeets, rphotos, rpubs, rswag, rtube, rwallet, rspace, rschedule
- **13 have NO real-time sync**: rchoices, rdata, rdesign, rdocs, rforum, rmeets, rphotos, rpubs, rswag, rtube, rwallet, rspace, rminders
## "Pull rApplet to rSpace" Pattern
A standardized UI component (`folk-applet-pull.ts`) that:
@ -42,7 +42,7 @@ rbooks, rcal, rcart, rfiles, rflows, rinbox, rnotes, rsocials, rsplat, rtasks, r
- **rchoices**: Add schema + local-first-client for voting sessions, live vote tallies
- **rswag**: Add schema for shared design state, collaborative editing
- **rwallet**: Add schema for shared wallet watchlist, collaborative treasury view
- **rschedule**: Already has schemas, needs local-first-client.ts + component sync
- **rminders**: Already has schemas, needs local-first-client.ts + component sync
- **rnetwork**: Already has WebSocket, add Automerge doc for CRM data persistence
### Tier 3 — UI-only wrappers, add lightweight sync (4 modules)

View File

@ -1,6 +1,6 @@
---
id: TASK-118.5
title: Add local-first-client to rschedule
title: Add local-first-client to rminders
status: Done
assignee: []
created_date: '2026-03-16 00:06'
@ -17,10 +17,10 @@ priority: medium
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
rschedule already has Automerge schemas but lacks a local-first-client.ts for client-side sync. Add the client and wire it into the 3 components (automation-canvas, reminders-widget, schedule-app).
rminders already has Automerge schemas but lacks a local-first-client.ts for client-side sync. Add the client and wire it into the 3 components (automation-canvas, reminders-widget, minders-app).
## New file:
- `modules/rschedule/local-first-client.ts` — wraps existing schemas with sync methods
- `modules/rminders/local-first-client.ts` — wraps existing schemas with sync methods
## Component updates:
- All 3 components init the client, subscribe, and react to remote changes

View File

@ -6,7 +6,7 @@ assignee: []
created_date: '2026-03-17 01:01'
labels:
- canvas
- rschedule
- rminders
- UX
dependencies: []
references:
@ -37,5 +37,5 @@ Add multiple UX affordances for scheduling reminders on canvas shapes: floating
## Final Summary
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
Implemented 4 reminder scheduling UX enhancements in `website/canvas.html` (156 insertions):\n\n1. **Right-click context menu** — \"📅 Schedule a reminder\" option in shape context menu opens reminder widget\n2. **Email notification** — Fetches user email from EncryptID `/auth/api/account/security`, caches it, passes `notifyEmail` to rSchedule API, shows confirmation in feedback\n3. **Floating calendar icon** — 28px circular 📅 button positioned at selected shape's top-right corner, repositions on scroll/zoom, toggles widget on click\n4. **Drag-to-calendar** — Compact calendar appears after 200ms of shape drag, day cells highlight on hover, releasing over a day creates the reminder
Implemented 4 reminder scheduling UX enhancements in `website/canvas.html` (156 insertions):\n\n1. **Right-click context menu** — \"📅 Schedule a reminder\" option in shape context menu opens reminder widget\n2. **Email notification** — Fetches user email from EncryptID `/auth/api/account/security`, caches it, passes `notifyEmail` to rMinders API, shows confirmation in feedback\n3. **Floating calendar icon** — 28px circular 📅 button positioned at selected shape's top-right corner, repositions on scroll/zoom, toggles widget on click\n4. **Drag-to-calendar** — Compact calendar appears after 200ms of shape drag, day cells highlight on hover, releasing over a day creates the reminder
<!-- SECTION:FINAL_SUMMARY:END -->

View File

@ -13,7 +13,7 @@ dependencies: []
references:
- modules/rchoices/mod.ts
- modules/rcal/mod.ts
- modules/rschedule/mod.ts
- modules/rminders/mod.ts
- server/index.ts (webhook pattern examples around line 2808)
priority: high
---
@ -30,7 +30,7 @@ Enable lightweight poll/RSVP responses via text message. Users send a text or cl
## Key integration points:
- **rChoices** (`modules/rchoices/`) — simple polls (vote/rank/spider)
- **rCal** (`modules/rcal/`) — event RSVPs (attendee fields exist but stub)
- **rSchedule** (`modules/rschedule/`) — could add SMS as action type for scheduled sends
- **rMinders** (`modules/rminders/`) — could add SMS as action type for scheduled sends
- **Existing webhook pattern** — follow payment webhook style (unauthenticated POST endpoints)
## Design notes from initial discussion:

View File

@ -33,6 +33,6 @@ export const MODULES: ModuleEntry[] = [
{ id: "rsplat", name: "rSplat", primarySelector: "folk-splat-viewer" },
{ id: "rphotos", name: "rPhotos", primarySelector: "folk-photo-gallery" },
{ id: "rsocials", name: "rSocials", primarySelector: undefined }, // HTML hub page, no main element
{ id: "rschedule", name: "rSchedule", primarySelector: "folk-schedule-app" },
{ id: "rminders", name: "rMinders", primarySelector: "folk-minders-app" },
{ id: "rmeets", name: "rMeets", primarySelector: undefined }, // HTML hub page
];

View File

@ -922,7 +922,7 @@ export class CommentPinManager {
};
if (email) body.notifyEmail = email;
const res = await fetch(`${getModuleApiBase("rschedule")}/api/reminders`, {
const res = await fetch(`${getModuleApiBase("rminders")}/api/reminders`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),

View File

@ -538,7 +538,7 @@ const WIDGET_API: Record<string, { path: string; transform: (data: any) => Widge
};
},
},
rschedule: {
rminders: {
path: "/api/jobs",
transform: (data) => {
const jobs = data?.results || [];

View File

@ -34,7 +34,7 @@ export const MODULE_META: Record<string, ModuleDisplayMeta> = {
rtrips: { badge: "rT", color: "#6ee7b7", name: "rTrips", icon: "✈️" },
rmaps: { badge: "rM", color: "#86efac", name: "rMaps", icon: "🗺️" },
rmeets: { badge: "rMe", color: "#6ee7b7", name: "rMeets", icon: "📹" },
rschedule: { badge: "rSc", color: "#93c5fd", name: "rSchedule", icon: "⏰" },
rminders: { badge: "rMi", color: "#93c5fd", name: "rMinders", icon: "⏰" },
rsocials: { badge: "rSo", color: "#f9a8d4", name: "rSocials", icon: "📱" },
rdesign: { badge: "rDe", color: "#7c3aed", name: "rDesign", icon: "🎨" },
rtime: { badge: "rTi", color: "#a78bfa", name: "rTime", icon: "⏳" },

View File

@ -1011,7 +1011,7 @@ class FolkCalendarView extends HTMLElement {
const virtualHtml = e.is_virtual ? `<span class="ev-virtual" title="Virtual">\u{1F4BB}</span>` : "";
const likelihoodHtml = es.isTentative ? `<span class="ev-likelihood">${es.likelihoodLabel}</span>` : "";
const lockHtml = e.accessVisibility && e.accessVisibility !== 'viewer' ? `<span class="membrane-lock" title="Restricted: ${e.accessVisibility} only">&#128274;</span> ` : "";
return `<div class="ev-label" style="border-left:2px ${es.borderStyle} ${evColor};background:${es.bgColor};opacity:${es.opacity}" data-event-id="${e.id}">${e.rToolSource === "rSchedule" ? '<span class="ev-bell">&#128276;</span>' : ""}${lockHtml}${virtualHtml}<span class="ev-time">${this.formatTime(e.start_time)}</span>${this.esc(e.title)}${likelihoodHtml}${cityHtml}</div>`;
return `<div class="ev-label" style="border-left:2px ${es.borderStyle} ${evColor};background:${es.bgColor};opacity:${es.opacity}" data-event-id="${e.id}">${e.rToolSource === "rMinders" ? '<span class="ev-bell">&#128276;</span>' : ""}${lockHtml}${virtualHtml}<span class="ev-time">${this.formatTime(e.start_time)}</span>${this.esc(e.title)}${likelihoodHtml}${cityHtml}</div>`;
}).join("");
}
@ -2284,7 +2284,7 @@ class FolkCalendarView extends HTMLElement {
private getScheduleApiBase(): string {
const path = window.location.pathname;
const match = path.match(/^(\/[^/]+)/);
return match ? `${match[1]}/rschedule` : "/rschedule";
return match ? `${match[1]}/rminders` : "/rminders";
}
private async handleReminderDrop(e: DragEvent, dropDate: string) {

View File

@ -447,7 +447,7 @@ routes.post("/api/events", async (c) => {
isVirtual: is_virtual || false,
virtualUrl: virtual_url || null,
virtualPlatform: virtual_platform || null,
rToolSource: r_tool_source || 'rSchedule',
rToolSource: r_tool_source || 'rMinders',
rToolEntityId: r_tool_entity_id || null,
attendees: [],
attendeeCount: 0,

View File

@ -729,10 +729,10 @@ class NotesCommentPanel extends HTMLElement {
// Set reminder on thread
let reminderId: string | undefined;
// Try creating a reminder via rSchedule API (non-demo only)
// Try creating a reminder via rMinders API (non-demo only)
if (!this.isDemo && this._space) {
try {
const res = await fetch(`${getModuleApiBase("rschedule")}/api/reminders`, {
const res = await fetch(`${getModuleApiBase("rminders")}/api/reminders`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...this.authHeaders() },
body: JSON.stringify({
@ -783,10 +783,10 @@ class NotesCommentPanel extends HTMLElement {
const thread = threads.find(t => t.id === threadId);
const reminderId = thread?.reminderId;
// Delete from rSchedule if exists
// Delete from rMinders if exists
if (reminderId && !this.isDemo && this._space) {
try {
await fetch(`${getModuleApiBase("rschedule")}/api/reminders/${reminderId}`, {
await fetch(`${getModuleApiBase("rminders")}/api/reminders/${reminderId}`, {
method: 'DELETE',
headers: this.authHeaders(),
});

View File

@ -88,7 +88,7 @@ export function renderLanding(): string {
<div class="rl-card rl-card--center">
<div class="rl-icon-box">&#128197;</div>
<h3>Calendar Integration</h3>
<p>Schedule meetings through rCal and rSchedule. Room links auto-generated, invites sent through your own mail server.</p>
<p>Schedule meetings through rCal and rMinders. Room links auto-generated, invites sent through your own mail server.</p>
</div>
<div class="rl-card rl-card--center">
<div class="rl-icon-box">&#128172;</div>

View File

@ -100,7 +100,7 @@ export function renderLanding(): string {
<div class="rl-card">
<div style="font-size:1.75rem;margin-bottom:1rem">&#128197;</div>
<h3>Shape Scheduling</h3>
<p>Tag any shape to a calendar date. Drag shapes onto the mini-calendar or click the schedule icon &mdash; reminders sync to rSchedule with email notifications.</p>
<p>Tag any shape to a calendar date. Drag shapes onto the mini-calendar or click the schedule icon &mdash; reminders sync to rMinders with email notifications.</p>
</div>
<div class="rl-card">
<div style="font-size:1.75rem;margin-bottom:1rem">&#128274;</div>

View File

@ -11,7 +11,7 @@ import { escapeHtml, escapeAttr, brandedAppName, MODULE_LANDING_CSS, RICH_LANDIN
/** Category → module IDs mapping for the tabbed showcase. */
const CATEGORY_GROUPS: Record<string, { label: string; icon: string; ids: string[] }> = {
plan: { label: "Plan", icon: "📋", ids: ["rcal", "rtasks", "rschedule", "rtime"] },
plan: { label: "Plan", icon: "📋", ids: ["rcal", "rtasks", "rminders", "rtime"] },
create: { label: "Create", icon: "✏️", ids: ["rspace", "rdocs", "rnotes", "rdesign", "rsplat", "rpubs", "rsheets", "rbooks"] },
communicate: { label: "Communicate", icon: "💬", ids: ["rchats", "rforum", "rinbox", "rmeets", "rsocials"] },
govern: { label: "Govern", icon: "⚖️", ids: ["rchoices", "rvote", "rgov", "crowdsurf"] },

View File

@ -7,7 +7,7 @@
*
* 108 tools across 36 groups:
* spaces (2), rcal (4), rnotes (5), rtasks (5), rwallet (4),
* rsocials (4), rnetwork (3), rinbox (4), rtime (4), rfiles (3), rschedule (4),
* rsocials (4), rnetwork (3), rinbox (4), rtime (4), rfiles (3), rminders (4),
* rvote (3), rchoices (3), rtrips (4), rcart (4), rexchange (4), rbnb (4),
* rvnb (3), crowdsurf (2), rbooks (2), rpubs (2), rmeets (2), rtube (2),
* rswag (2), rdesign (2), rsplat (2), rphotos (2), rflows (2), rdocs (5),
@ -31,7 +31,7 @@ import { registerNetworkTools } from "./mcp-tools/rnetwork";
import { registerInboxTools } from "./mcp-tools/rinbox";
import { registerTimeTools } from "./mcp-tools/rtime";
import { registerFilesTools } from "./mcp-tools/rfiles";
import { registerScheduleTools } from "./mcp-tools/rschedule";
import { registerMindersTools } from "./mcp-tools/rminders";
import { registerVoteTools } from "./mcp-tools/rvote";
import { registerChoicesTools } from "./mcp-tools/rchoices";
import { registerTripsTools } from "./mcp-tools/rtrips";
@ -75,7 +75,7 @@ function createMcpServerInstance(syncServer: SyncServer): McpServer {
registerInboxTools(server, syncServer);
registerTimeTools(server, syncServer);
registerFilesTools(server, syncServer);
registerScheduleTools(server, syncServer);
registerMindersTools(server, syncServer);
registerVoteTools(server, syncServer);
registerChoicesTools(server, syncServer);
registerTripsTools(server, syncServer);

View File

@ -14,7 +14,7 @@ import { getRecentContactsForMI } from "../modules/rnetwork/mod";
import { getRecentThreadsForMI } from "../modules/rinbox/mod";
import { getRecentCommitmentsForMI } from "../modules/rtime/mod";
import { getRecentFilesForMI } from "../modules/rfiles/mod";
import { getUpcomingRemindersForMI } from "../modules/rschedule/mod";
import { getUpcomingRemindersForMI } from "../modules/rminders/mod";
import { getMapPinsForMI } from "../modules/rmaps/mod";
import { getRecentMeetingsForMI } from "../modules/rmeets/mod";
import { getRecentVideosForMI } from "../modules/rtube/mod";
@ -139,7 +139,7 @@ export function queryModuleContent(
return { ok: true, module, queryType, data: files, summary: lines.length ? `Recent files:\n${lines.join("\n")}` : "No files found." };
}
case "rschedule": {
case "rminders": {
const reminders = getUpcomingRemindersForMI(space, 14, limit);
if (queryType === "count") {
return { ok: true, module, queryType, data: { count: reminders.length }, summary: `${reminders.length} upcoming reminders.` };

View File

@ -272,7 +272,7 @@ When you need to look up the user's actual data (notes, tasks, events):
[MI_ACTION:{"type":"query-content","module":"rinbox","queryType":"recent","limit":5}]
[MI_ACTION:{"type":"query-content","module":"rtime","queryType":"recent","limit":5}]
[MI_ACTION:{"type":"query-content","module":"rfiles","queryType":"recent","limit":5}]
[MI_ACTION:{"type":"query-content","module":"rschedule","queryType":"recent","limit":5}]
[MI_ACTION:{"type":"query-content","module":"rminders","queryType":"recent","limit":5}]
[MI_ACTION:{"type":"query-content","module":"rmaps","queryType":"recent","limit":5}]
[MI_ACTION:{"type":"query-content","module":"rmeets","queryType":"recent","limit":5}]
[MI_ACTION:{"type":"query-content","module":"rtube","queryType":"recent","limit":5}]

View File

@ -139,11 +139,11 @@ Shared calendar with external sync.
- **Event creation** shared community events`,
},
{
id: "demo-tool-rschedule",
id: "demo-tool-rminders",
type: "folk-markdown",
...pos(2, 1), width: CARD_W, height: CARD_H, rotation: 0,
content: `### rSchedule
Automations and scheduled jobs.
content: `### rMinders
Automations, reminders, and scheduled jobs.
- **Cron jobs** recurring tasks on a schedule
- **Reminders** email notifications

View File

@ -31,7 +31,7 @@ const FAVICON_BADGE_MAP: Record<string, { badge: string; color: string }> = {
rmeets: { badge: "r📹", color: "#67e8f9" },
rcal: { badge: "r📅", color: "#7dd3fc" },
rchoices: { badge: "r☑", color: "#f0abfc" },
rschedule: { badge: "r⏱", color: "#a5b4fc" },
rminders: { badge: "r⏱", color: "#a5b4fc" },
rtasks: { badge: "r📋", color: "#cbd5e1" },
rtime: { badge: "r⏳", color: "#a78bfa" },
rvote: { badge: "r🗳", color: "#c4b5fd" },

View File

@ -18,7 +18,7 @@ import { getRecentContactsForMI } from "../modules/rnetwork/mod";
import { getRecentThreadsForMI } from "../modules/rinbox/mod";
import { getRecentCommitmentsForMI } from "../modules/rtime/mod";
import { getRecentFilesForMI } from "../modules/rfiles/mod";
import { getUpcomingRemindersForMI } from "../modules/rschedule/mod";
import { getUpcomingRemindersForMI } from "../modules/rminders/mod";
import { getMapPinsForMI } from "../modules/rmaps/mod";
import { getRecentMeetingsForMI } from "../modules/rmeets/mod";
import { getRecentVideosForMI } from "../modules/rtube/mod";
@ -244,7 +244,7 @@ class SpaceKnowledgeIndex {
const safeTitle = sanitizeForPrompt(r.title, MAX_TITLE_LENGTH);
const line = `${date}: ${safeTitle}${r.sourceModule ? ` (from ${r.sourceModule})` : ""}`;
entries.push({
id: `rschedule:${r.id}`, moduleId: "rschedule", category: "time",
id: `rminders:${r.id}`, moduleId: "rminders", category: "time",
title: safeTitle, detail: r.sourceModule || "",
tags: [r.sourceModule].filter(Boolean) as string[],
timestamp: r.remindAt || now, formatted: line,

View File

@ -38,7 +38,7 @@ const MODULE_BADGES: Record<string, { badge: string; color: string }> = {
// Coordinate
rcal: { badge: "r📅", color: "#7dd3fc" }, // sky-300
rchoices: { badge: "r☑", color: "#f0abfc" }, // fuchsia-300
rschedule: { badge: "r⏱", color: "#a5b4fc" }, // indigo-200
rminders: { badge: "r⏱", color: "#a5b4fc" }, // indigo-200
rtasks: { badge: "r📋", color: "#cbd5e1" }, // slate-300
rtime: { badge: "r⏳", color: "#a78bfa" }, // violet-400
rvote: { badge: "r🗳", color: "#c4b5fd" }, // violet-300
@ -94,7 +94,7 @@ const MODULE_CATEGORIES: Record<string, string> = {
crowdsurf: "Coordinate",
rcal: "Coordinate",
rchoices: "Coordinate",
rschedule: "Coordinate",
rminders: "Coordinate",
rtasks: "Coordinate",
rtime: "Coordinate",
rvote: "Coordinate",

View File

@ -53,7 +53,7 @@ const MODULE_BADGES: Record<string, { badge: string; color: string }> = {
rbooks: { badge: "r📚", color: "#fda4af" },
rdata: { badge: "r📊", color: "#d8b4fe" },
rtasks: { badge: "r📋", color: "#cbd5e1" },
rschedule: { badge: "r⏱", color: "#a5b4fc" },
rminders: { badge: "r⏱", color: "#a5b4fc" },
rids: { badge: "r🪪", color: "#6ee7b7" },
rcred: { badge: "r⭐", color: "#d97706" },
rstack: { badge: "r✨", color: "" },

View File

@ -3,7 +3,7 @@
*
* Two complementary projections:
* - **Scheduled** (MarkwhenSourceFactory): "what's happening / will happen"
* events with explicit start/end (rCal, rSchedule).
* events with explicit start/end (rCal, rMinders).
* - **Creations** (CreationEnumerator / CreationSpec): "what has been made"
* every CRDT record's birth moment across every rApp. This is what rPast
* renders. Declared statically in `creation-specs.ts`.

View File

@ -13,7 +13,7 @@ const TAG_COLOR_DEFAULTS: Record<string, string> = {
rnotes: 'green',
rtasks: 'orange',
rvote: 'purple',
rschedule: 'teal',
rminders: 'teal',
rtrips: 'amber',
rinbox: 'gray',
};

View File

@ -1384,42 +1384,42 @@ export default defineConfig({
resolve(__dirname, "dist/modules/rphotos/photos.css"),
);
// Build schedule module component
// Build minders module component
await wasmBuild({
configFile: false,
root: resolve(__dirname, "modules/rschedule/components"),
root: resolve(__dirname, "modules/rminders/components"),
build: {
emptyOutDir: false,
outDir: resolve(__dirname, "dist/modules/rschedule"),
outDir: resolve(__dirname, "dist/modules/rminders"),
lib: {
entry: resolve(__dirname, "modules/rschedule/components/folk-schedule-app.ts"),
entry: resolve(__dirname, "modules/rminders/components/folk-minders-app.ts"),
formats: ["es"],
fileName: () => "folk-schedule-app.js",
fileName: () => "folk-minders-app.js",
},
rollupOptions: {
output: {
entryFileNames: "folk-schedule-app.js",
entryFileNames: "folk-minders-app.js",
},
},
},
});
// Copy schedule CSS
mkdirSync(resolve(__dirname, "dist/modules/rschedule"), { recursive: true });
// Copy minders CSS
mkdirSync(resolve(__dirname, "dist/modules/rminders"), { recursive: true });
copyFileSync(
resolve(__dirname, "modules/rschedule/components/schedule.css"),
resolve(__dirname, "dist/modules/rschedule/schedule.css"),
resolve(__dirname, "modules/rminders/components/minders.css"),
resolve(__dirname, "dist/modules/rminders/minders.css"),
);
// Build schedule reminders widget component
// Build minders reminders widget component
await wasmBuild({
configFile: false,
root: resolve(__dirname, "modules/rschedule/components"),
root: resolve(__dirname, "modules/rminders/components"),
build: {
emptyOutDir: false,
outDir: resolve(__dirname, "dist/modules/rschedule"),
outDir: resolve(__dirname, "dist/modules/rminders"),
lib: {
entry: resolve(__dirname, "modules/rschedule/components/folk-reminders-widget.ts"),
entry: resolve(__dirname, "modules/rminders/components/folk-reminders-widget.ts"),
formats: ["es"],
fileName: () => "folk-reminders-widget.js",
},
@ -1431,20 +1431,20 @@ export default defineConfig({
},
});
// Build schedule automation canvas component
// Build minders automation canvas component
await wasmBuild({
configFile: false,
root: resolve(__dirname, "modules/rschedule/components"),
root: resolve(__dirname, "modules/rminders/components"),
resolve: {
alias: {
"../schemas": resolve(__dirname, "modules/rschedule/schemas.ts"),
"../schemas": resolve(__dirname, "modules/rminders/schemas.ts"),
},
},
build: {
emptyOutDir: false,
outDir: resolve(__dirname, "dist/modules/rschedule"),
outDir: resolve(__dirname, "dist/modules/rminders"),
lib: {
entry: resolve(__dirname, "modules/rschedule/components/folk-automation-canvas.ts"),
entry: resolve(__dirname, "modules/rminders/components/folk-automation-canvas.ts"),
formats: ["es"],
fileName: () => "folk-automation-canvas.js",
},
@ -1458,8 +1458,8 @@ export default defineConfig({
// Copy automation canvas CSS
copyFileSync(
resolve(__dirname, "modules/rschedule/components/automation-canvas.css"),
resolve(__dirname, "dist/modules/rschedule/automation-canvas.css"),
resolve(__dirname, "modules/rminders/components/automation-canvas.css"),
resolve(__dirname, "dist/modules/rminders/automation-canvas.css"),
);
// ── Demo infrastructure ──

View File

@ -8290,7 +8290,7 @@ Use real coordinates, YYYY-MM-DD dates, ISO currency codes. Ask clarifying quest
if (!rwSelectedShape) return;
const info = getShapeInfo(rwSelectedShape);
const remindAt = new Date(dateStr + "T09:00:00").getTime();
const schedBase = `/${communitySlug}/rschedule`;
const schedBase = `/${communitySlug}/rminders`;
// Fetch user email for notification (cached after first call)
if (cachedUserEmail === null) {