Merge branch 'dev'
CI/CD / deploy (push) Waiting to run
Details
CI/CD / deploy (push) Waiting to run
Details
This commit is contained in:
commit
007df8a3bd
|
|
@ -14,6 +14,8 @@ export interface CanvasToolDefinition {
|
|||
};
|
||||
};
|
||||
tagName: string;
|
||||
/** Module that owns this tool (omit for core/always-available tools) */
|
||||
moduleId?: string;
|
||||
buildProps: (args: Record<string, any>) => Record<string, any>;
|
||||
actionLabel: (args: Record<string, any>) => string;
|
||||
}
|
||||
|
|
@ -35,6 +37,7 @@ const registry: CanvasToolDefinition[] = [
|
|||
},
|
||||
},
|
||||
tagName: "folk-map",
|
||||
moduleId: "rmaps",
|
||||
buildProps: (args) => ({
|
||||
center: [args.longitude, args.latitude],
|
||||
zoom: args.zoom || 12,
|
||||
|
|
@ -161,6 +164,7 @@ const registry: CanvasToolDefinition[] = [
|
|||
},
|
||||
},
|
||||
tagName: "folk-destination",
|
||||
moduleId: "rtrips",
|
||||
buildProps: (args) => ({
|
||||
destName: args.destName,
|
||||
...(args.country ? { country: args.country } : {}),
|
||||
|
|
@ -186,6 +190,7 @@ const registry: CanvasToolDefinition[] = [
|
|||
},
|
||||
},
|
||||
tagName: "folk-itinerary",
|
||||
moduleId: "rtrips",
|
||||
buildProps: (args) => {
|
||||
let items: any[] = [];
|
||||
try { items = JSON.parse(args.itemsJson); } catch { items = []; }
|
||||
|
|
@ -217,6 +222,7 @@ const registry: CanvasToolDefinition[] = [
|
|||
},
|
||||
},
|
||||
tagName: "folk-booking",
|
||||
moduleId: "rtrips",
|
||||
buildProps: (args) => ({
|
||||
bookingType: args.bookingType,
|
||||
provider: args.provider,
|
||||
|
|
@ -244,6 +250,7 @@ const registry: CanvasToolDefinition[] = [
|
|||
},
|
||||
},
|
||||
tagName: "folk-budget",
|
||||
moduleId: "rtrips",
|
||||
buildProps: (args) => {
|
||||
let expenses: any[] = [];
|
||||
try { expenses = JSON.parse(args.expensesJson); } catch { expenses = []; }
|
||||
|
|
@ -268,6 +275,7 @@ const registry: CanvasToolDefinition[] = [
|
|||
},
|
||||
},
|
||||
tagName: "folk-packing-list",
|
||||
moduleId: "rtrips",
|
||||
buildProps: (args) => {
|
||||
let items: any[] = [];
|
||||
try { items = JSON.parse(args.itemsJson); } catch { items = []; }
|
||||
|
|
@ -320,6 +328,7 @@ registry.push(
|
|||
},
|
||||
},
|
||||
tagName: "folk-social-post",
|
||||
moduleId: "rsocials",
|
||||
buildProps: (args) => ({
|
||||
platform: args.platform || "x",
|
||||
content: args.content,
|
||||
|
|
@ -346,6 +355,7 @@ registry.push(
|
|||
},
|
||||
},
|
||||
tagName: "folk-social-thread",
|
||||
moduleId: "rsocials",
|
||||
buildProps: (args) => {
|
||||
let tweets: string[] = [];
|
||||
try { tweets = JSON.parse(args.tweetsJson || "[]"); } catch { tweets = []; }
|
||||
|
|
@ -374,6 +384,7 @@ registry.push(
|
|||
},
|
||||
},
|
||||
tagName: "folk-social-campaign",
|
||||
moduleId: "rsocials",
|
||||
buildProps: (args) => ({
|
||||
title: args.title,
|
||||
description: args.description || "",
|
||||
|
|
@ -398,6 +409,7 @@ registry.push(
|
|||
},
|
||||
},
|
||||
tagName: "folk-social-newsletter",
|
||||
moduleId: "rsocials",
|
||||
buildProps: (args) => ({
|
||||
subject: args.subject,
|
||||
listName: args.listName || "",
|
||||
|
|
@ -423,6 +435,7 @@ registry.push(
|
|||
},
|
||||
},
|
||||
tagName: "folk-commitment-pool",
|
||||
moduleId: "rtime",
|
||||
buildProps: (args) => ({
|
||||
spaceSlug: args.spaceSlug || "demo",
|
||||
}),
|
||||
|
|
@ -443,6 +456,7 @@ registry.push(
|
|||
},
|
||||
},
|
||||
tagName: "folk-task-request",
|
||||
moduleId: "rtime",
|
||||
buildProps: (args) => {
|
||||
let needs: Record<string, number> = {};
|
||||
try { needs = JSON.parse(args.needsJson || "{}"); } catch { needs = {}; }
|
||||
|
|
@ -470,6 +484,7 @@ registry.push({
|
|||
},
|
||||
},
|
||||
tagName: "folk-design-agent",
|
||||
moduleId: "rdesign",
|
||||
buildProps: (args) => ({ brief: args.brief || "" }),
|
||||
actionLabel: (args) => `Opened design agent${args.brief ? `: ${args.brief.slice(0, 50)}` : ""}`,
|
||||
});
|
||||
|
|
@ -485,3 +500,11 @@ export function findTool(name: string): CanvasToolDefinition | undefined {
|
|||
export function registerCanvasTool(def: CanvasToolDefinition): void {
|
||||
CANVAS_TOOLS.push(def);
|
||||
}
|
||||
|
||||
/** Return tools available for the given set of enabled modules.
|
||||
* If enabledIds is null/undefined, all tools are returned (all modules enabled). */
|
||||
export function getToolsForModules(enabledIds: string[] | null | undefined): CanvasToolDefinition[] {
|
||||
if (!enabledIds) return CANVAS_TOOLS;
|
||||
const enabled = new Set(enabledIds);
|
||||
return CANVAS_TOOLS.filter(t => !t.moduleId || enabled.has(t.moduleId));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,6 +198,48 @@ export class FolkCommitmentPool extends FolkShape {
|
|||
this.styles = sheet;
|
||||
}
|
||||
|
||||
// ── Module-disabled gating ──
|
||||
static #enabledModules: Set<string> | null = null;
|
||||
static #instances = new Set<FolkCommitmentPool>();
|
||||
|
||||
static setEnabledModules(ids: string[] | null) {
|
||||
FolkCommitmentPool.#enabledModules = ids ? new Set(ids) : null;
|
||||
for (const inst of FolkCommitmentPool.#instances) inst.#syncDisabledState();
|
||||
}
|
||||
|
||||
#isModuleDisabled(): boolean {
|
||||
const enabled = FolkCommitmentPool.#enabledModules;
|
||||
if (!enabled) return false;
|
||||
return !enabled.has("rtime");
|
||||
}
|
||||
|
||||
#syncDisabledState() {
|
||||
if (!this.#wrapper) return;
|
||||
const disabled = this.#isModuleDisabled();
|
||||
const wasDisabled = this.hasAttribute("data-module-disabled");
|
||||
if (disabled && !wasDisabled) {
|
||||
this.#showDisabledOverlay();
|
||||
} else if (!disabled && wasDisabled) {
|
||||
this.removeAttribute("data-module-disabled");
|
||||
this.#wrapper.querySelector(".disabled-overlay")?.remove();
|
||||
this.#fetchCommitments();
|
||||
this.#startAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
#showDisabledOverlay() {
|
||||
this.setAttribute("data-module-disabled", "");
|
||||
if (this.#animFrame) { cancelAnimationFrame(this.#animFrame); this.#animFrame = 0; }
|
||||
let overlay = this.#wrapper?.querySelector(".disabled-overlay") as HTMLElement;
|
||||
if (!overlay && this.#wrapper) {
|
||||
overlay = document.createElement("div");
|
||||
overlay.className = "disabled-overlay";
|
||||
overlay.style.cssText = "position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:8px;background:rgba(15,23,42,0.85);border-radius:inherit;z-index:10;color:#94a3b8;font-size:13px;";
|
||||
overlay.innerHTML = '<span style="font-size:24px">🔒</span><span>rTime is disabled</span>';
|
||||
this.#wrapper.appendChild(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
#spaceSlug = "demo";
|
||||
#canvas!: HTMLCanvasElement;
|
||||
#ctx!: CanvasRenderingContext2D;
|
||||
|
|
@ -234,13 +276,20 @@ export class FolkCommitmentPool extends FolkShape {
|
|||
this.#canvas.addEventListener("pointerdown", this.#onPointerDown);
|
||||
this.#canvas.addEventListener("pointerleave", () => { this.#hoveredOrb = null; });
|
||||
|
||||
this.#fetchCommitments();
|
||||
this.#startAnimation();
|
||||
FolkCommitmentPool.#instances.add(this);
|
||||
|
||||
if (this.#isModuleDisabled()) {
|
||||
this.#showDisabledOverlay();
|
||||
} else {
|
||||
this.#fetchCommitments();
|
||||
this.#startAnimation();
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
FolkCommitmentPool.#instances.delete(this);
|
||||
if (this.#animFrame) cancelAnimationFrame(this.#animFrame);
|
||||
this.#animFrame = 0;
|
||||
this.#removeGhost();
|
||||
|
|
|
|||
|
|
@ -648,6 +648,7 @@ export class FolkPrompt extends FolkShape {
|
|||
})),
|
||||
model: this.#model,
|
||||
...(useTools ? { useTools: true, systemPrompt: this.#systemPrompt || undefined } : {}),
|
||||
...(useTools && (window as any).__rspaceEnabledModules ? { enabledModules: (window as any).__rspaceEnabledModules } : {}),
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { FolkShape } from "./folk-shape";
|
||||
import { css, html } from "./tags";
|
||||
import { rspaceNavUrl } from "../shared/url-helpers";
|
||||
import { MODULE_META } from "./module-display";
|
||||
import type { PortDescriptor } from "./data-types";
|
||||
|
||||
/**
|
||||
|
|
@ -16,35 +17,6 @@ import type { PortDescriptor } from "./data-types";
|
|||
* iframe → parent: { source: "rspace-rapp", type: "navigate", moduleId }
|
||||
*/
|
||||
|
||||
// Module metadata for header display (subset of rstack-app-switcher badges)
|
||||
const MODULE_META: Record<string, { badge: string; color: string; name: string; icon: string }> = {
|
||||
rnotes: { badge: "rN", color: "#fcd34d", name: "rNotes", icon: "📝" },
|
||||
rphotos: { badge: "rPh", color: "#f9a8d4", name: "rPhotos", icon: "📸" },
|
||||
rbooks: { badge: "rB", color: "#fda4af", name: "rBooks", icon: "📚" },
|
||||
rpubs: { badge: "rP", color: "#fda4af", name: "rPubs", icon: "📖" },
|
||||
rfiles: { badge: "rFi", color: "#67e8f9", name: "rFiles", icon: "📁" },
|
||||
rtasks: { badge: "rTa", color: "#cbd5e1", name: "rTasks", icon: "📋" },
|
||||
rforum: { badge: "rFo", color: "#fcd34d", name: "rForum", icon: "💬" },
|
||||
rinbox: { badge: "rI", color: "#a5b4fc", name: "rInbox", icon: "📧" },
|
||||
rtube: { badge: "rTu", color: "#f9a8d4", name: "rTube", icon: "🎬" },
|
||||
rflows: { badge: "rFl", color: "#bef264", name: "rFlows", icon: "🌊" },
|
||||
rwallet: { badge: "rW", color: "#fde047", name: "rWallet", icon: "💰" },
|
||||
rvote: { badge: "rV", color: "#c4b5fd", name: "rVote", icon: "🗳️" },
|
||||
rcart: { badge: "rCt", color: "#fdba74", name: "rCart", icon: "🛒" },
|
||||
rdata: { badge: "rD", color: "#d8b4fe", name: "rData", icon: "📊" },
|
||||
rnetwork: { badge: "rNe", color: "#93c5fd", name: "rNetwork", icon: "🌍" },
|
||||
rsplat: { badge: "r3", color: "#d8b4fe", name: "rSplat", icon: "🔮" },
|
||||
rswag: { badge: "rSw", color: "#fda4af", name: "rSwag", icon: "🎨" },
|
||||
rchoices: { badge: "rCo", color: "#f0abfc", name: "rChoices", icon: "🤔" },
|
||||
rcal: { badge: "rC", color: "#7dd3fc", name: "rCal", icon: "📅" },
|
||||
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: "⏰" },
|
||||
rsocials: { badge: "rSo", color: "#f9a8d4", name: "rSocials", icon: "📱" },
|
||||
rdesign: { badge: "rDe", color: "#7c3aed", name: "rDesign", icon: "🎨" },
|
||||
};
|
||||
|
||||
const styles = css`
|
||||
:host {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -139,6 +139,45 @@ export class FolkTaskRequest extends FolkShape {
|
|||
this.styles = sheet;
|
||||
}
|
||||
|
||||
// ── Module-disabled gating ──
|
||||
static #enabledModules: Set<string> | null = null;
|
||||
static #instances = new Set<FolkTaskRequest>();
|
||||
|
||||
static setEnabledModules(ids: string[] | null) {
|
||||
FolkTaskRequest.#enabledModules = ids ? new Set(ids) : null;
|
||||
for (const inst of FolkTaskRequest.#instances) inst.#syncDisabledState();
|
||||
}
|
||||
|
||||
#isModuleDisabled(): boolean {
|
||||
const enabled = FolkTaskRequest.#enabledModules;
|
||||
if (!enabled) return false;
|
||||
return !enabled.has("rtime");
|
||||
}
|
||||
|
||||
#syncDisabledState() {
|
||||
if (!this.#wrapper) return;
|
||||
const disabled = this.#isModuleDisabled();
|
||||
const wasDisabled = this.hasAttribute("data-module-disabled");
|
||||
if (disabled && !wasDisabled) {
|
||||
this.#showDisabledOverlay();
|
||||
} else if (!disabled && wasDisabled) {
|
||||
this.removeAttribute("data-module-disabled");
|
||||
this.#wrapper.querySelector(".disabled-overlay")?.remove();
|
||||
}
|
||||
}
|
||||
|
||||
#showDisabledOverlay() {
|
||||
this.setAttribute("data-module-disabled", "");
|
||||
let overlay = this.#wrapper?.querySelector(".disabled-overlay") as HTMLElement;
|
||||
if (!overlay && this.#wrapper) {
|
||||
overlay = document.createElement("div");
|
||||
overlay.className = "disabled-overlay";
|
||||
overlay.style.cssText = "position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:8px;background:rgba(15,23,42,0.85);border-radius:inherit;z-index:10;color:#94a3b8;font-size:13px;";
|
||||
overlay.innerHTML = '<span style="font-size:24px">🔒</span><span>rTime is disabled</span>';
|
||||
this.#wrapper.appendChild(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
#taskId = "";
|
||||
#spaceSlug = "demo";
|
||||
#taskName = "New Task";
|
||||
|
|
@ -234,10 +273,14 @@ export class FolkTaskRequest extends FolkShape {
|
|||
document.addEventListener("commitment-drag-move", this.#onDragMove as EventListener);
|
||||
document.addEventListener("commitment-drag-end", this.#onDragEnd as EventListener);
|
||||
|
||||
FolkTaskRequest.#instances.add(this);
|
||||
if (this.#isModuleDisabled()) this.#showDisabledOverlay();
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
FolkTaskRequest.#instances.delete(this);
|
||||
document.removeEventListener("commitment-drag-start", this.#onDragStart as EventListener);
|
||||
document.removeEventListener("commitment-drag-move", this.#onDragMove as EventListener);
|
||||
document.removeEventListener("commitment-drag-end", this.#onDragEnd as EventListener);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Module display metadata — badge colors, names, icons for canvas UI.
|
||||
* Extracted from folk-rapp.ts so both folk-rapp and future display code
|
||||
* can share a single source of truth.
|
||||
*/
|
||||
|
||||
export interface ModuleDisplayMeta {
|
||||
badge: string;
|
||||
color: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
export const MODULE_META: Record<string, ModuleDisplayMeta> = {
|
||||
rnotes: { badge: "rN", color: "#fcd34d", name: "rNotes", icon: "📝" },
|
||||
rphotos: { badge: "rPh", color: "#f9a8d4", name: "rPhotos", icon: "📸" },
|
||||
rbooks: { badge: "rB", color: "#fda4af", name: "rBooks", icon: "📚" },
|
||||
rpubs: { badge: "rP", color: "#fda4af", name: "rPubs", icon: "📖" },
|
||||
rfiles: { badge: "rFi", color: "#67e8f9", name: "rFiles", icon: "📁" },
|
||||
rtasks: { badge: "rTa", color: "#cbd5e1", name: "rTasks", icon: "📋" },
|
||||
rforum: { badge: "rFo", color: "#fcd34d", name: "rForum", icon: "💬" },
|
||||
rinbox: { badge: "rI", color: "#a5b4fc", name: "rInbox", icon: "📧" },
|
||||
rtube: { badge: "rTu", color: "#f9a8d4", name: "rTube", icon: "🎬" },
|
||||
rflows: { badge: "rFl", color: "#bef264", name: "rFlows", icon: "🌊" },
|
||||
rwallet: { badge: "rW", color: "#fde047", name: "rWallet", icon: "💰" },
|
||||
rvote: { badge: "rV", color: "#c4b5fd", name: "rVote", icon: "🗳️" },
|
||||
rcart: { badge: "rCt", color: "#fdba74", name: "rCart", icon: "🛒" },
|
||||
rdata: { badge: "rD", color: "#d8b4fe", name: "rData", icon: "📊" },
|
||||
rnetwork: { badge: "rNe", color: "#93c5fd", name: "rNetwork", icon: "🌍" },
|
||||
rsplat: { badge: "r3", color: "#d8b4fe", name: "rSplat", icon: "🔮" },
|
||||
rswag: { badge: "rSw", color: "#fda4af", name: "rSwag", icon: "🎨" },
|
||||
rchoices: { badge: "rCo", color: "#f0abfc", name: "rChoices", icon: "🤔" },
|
||||
rcal: { badge: "rC", color: "#7dd3fc", name: "rCal", icon: "📅" },
|
||||
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: "⏰" },
|
||||
rsocials: { badge: "rSo", color: "#f9a8d4", name: "rSocials", icon: "📱" },
|
||||
rdesign: { badge: "rDe", color: "#7c3aed", name: "rDesign", icon: "🎨" },
|
||||
rtime: { badge: "rTi", color: "#a78bfa", name: "rTime", icon: "⏳" },
|
||||
};
|
||||
|
|
@ -19,12 +19,23 @@ export interface ShapeRegistration {
|
|||
|
||||
class ShapeRegistry {
|
||||
#registrations = new Map<string, ShapeRegistration>();
|
||||
#moduleMap = new Map<string, string>();
|
||||
|
||||
/** Register a shape type. */
|
||||
register(tagName: string, elementClass: ShapeRegistration["elementClass"]): void {
|
||||
this.#registrations.set(tagName, { tagName, elementClass });
|
||||
}
|
||||
|
||||
/** Associate a shape tag with a module ID. */
|
||||
setModule(tagName: string, moduleId: string): void {
|
||||
this.#moduleMap.set(tagName, moduleId);
|
||||
}
|
||||
|
||||
/** Get the owning module ID for a shape tag, or undefined if core/always-available. */
|
||||
moduleOf(tagName: string): string | undefined {
|
||||
return this.#moduleMap.get(tagName);
|
||||
}
|
||||
|
||||
/** Get registration for a tag name. */
|
||||
getRegistration(tagName: string): ShapeRegistration | undefined {
|
||||
return this.#registrations.get(tagName);
|
||||
|
|
|
|||
|
|
@ -1082,6 +1082,7 @@ export const calModule: RSpaceModule = {
|
|||
name: "rCal",
|
||||
icon: "📅",
|
||||
description: "Temporal coordination calendar with lunar, solar, and seasonal systems",
|
||||
canvasShapes: ["folk-calendar"],
|
||||
scoping: { defaultScope: 'global', userConfigurable: true },
|
||||
docSchemas: [{ pattern: '{space}:cal:events', description: 'Calendar events and sources', init: calendarSchema.init }],
|
||||
routes,
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ export const choicesModule: RSpaceModule = {
|
|||
name: "rChoices",
|
||||
icon: "☑",
|
||||
description: "Polls, rankings, and multi-criteria scoring",
|
||||
canvasShapes: ["folk-choice-vote", "folk-choice-rank", "folk-choice-spider", "folk-spider-3d", "folk-choice-conviction"],
|
||||
scoping: { defaultScope: 'space', userConfigurable: false },
|
||||
routes,
|
||||
standaloneDomain: "rchoices.online",
|
||||
|
|
|
|||
|
|
@ -673,6 +673,8 @@ export const designModule: RSpaceModule = {
|
|||
name: "rDesign",
|
||||
icon: "🎨",
|
||||
description: "AI-powered DTP workspace — text in, design out",
|
||||
canvasShapes: ["folk-design-agent"],
|
||||
canvasToolIds: ["create_design_agent"],
|
||||
scoping: { defaultScope: 'global', userConfigurable: false },
|
||||
publicWrite: true,
|
||||
routes,
|
||||
|
|
|
|||
|
|
@ -304,6 +304,8 @@ export const mapsModule: RSpaceModule = {
|
|||
name: "rMaps",
|
||||
icon: "🗺",
|
||||
description: "Real-time collaborative location sharing and indoor/outdoor maps",
|
||||
canvasShapes: ["folk-map"],
|
||||
canvasToolIds: ["create_map"],
|
||||
scoping: { defaultScope: 'global', userConfigurable: false },
|
||||
routes,
|
||||
landingPage: renderLanding,
|
||||
|
|
|
|||
|
|
@ -2270,6 +2270,8 @@ export const socialsModule: RSpaceModule = {
|
|||
name: "rSocials",
|
||||
icon: "📢",
|
||||
description: "Federated social feed aggregator for communities",
|
||||
canvasShapes: ["folk-social-post", "folk-social-thread", "folk-social-campaign", "folk-social-newsletter"],
|
||||
canvasToolIds: ["create_social_post", "create_social_thread", "create_campaign_card", "create_newsletter_card"],
|
||||
scoping: { defaultScope: "space", userConfigurable: true },
|
||||
docSchemas: [{ pattern: "{space}:socials:data", description: "Threads and campaigns", init: socialsSchema.init }],
|
||||
routes,
|
||||
|
|
|
|||
|
|
@ -863,6 +863,7 @@ export const splatModule: RSpaceModule = {
|
|||
name: "rSplat",
|
||||
icon: "🔮",
|
||||
description: "3D Gaussian splat viewer",
|
||||
canvasShapes: ["folk-splat"],
|
||||
publicWrite: true,
|
||||
scoping: { defaultScope: 'global', userConfigurable: true },
|
||||
docSchemas: [{ pattern: '{space}:splat:scenes', description: 'Splat scene metadata', init: splatScenesSchema.init }],
|
||||
|
|
|
|||
|
|
@ -439,6 +439,8 @@ export const timeModule: RSpaceModule = {
|
|||
name: "rTime",
|
||||
icon: "⏳",
|
||||
description: "Timebank commitment pool & weaving dashboard",
|
||||
canvasShapes: ["folk-commitment-pool", "folk-task-request"],
|
||||
canvasToolIds: ["create_commitment_pool", "create_task_request"],
|
||||
scoping: { defaultScope: 'space', userConfigurable: false },
|
||||
docSchemas: [
|
||||
{ pattern: '{space}:rtime:commitments', description: 'Commitment pool', init: commitmentsSchema.init },
|
||||
|
|
|
|||
|
|
@ -754,6 +754,8 @@ export const tripsModule: RSpaceModule = {
|
|||
name: "rTrips",
|
||||
icon: "✈️",
|
||||
description: "Collaborative trip planner with itinerary, bookings, and expense splitting",
|
||||
canvasShapes: ["folk-itinerary", "folk-destination", "folk-budget", "folk-packing-list", "folk-booking"],
|
||||
canvasToolIds: ["create_destination", "create_itinerary", "create_booking", "create_budget", "create_packing_list"],
|
||||
scoping: { defaultScope: 'global', userConfigurable: true },
|
||||
docSchemas: [{ pattern: '{space}:trips:trips:{tripId}', description: 'Trip with destinations and itinerary', init: tripSchema.init }],
|
||||
routes,
|
||||
|
|
|
|||
|
|
@ -1294,6 +1294,7 @@ export const walletModule: RSpaceModule = {
|
|||
name: "rWallet",
|
||||
icon: "💰",
|
||||
description: "Multichain Safe wallet visualization and treasury management",
|
||||
canvasShapes: ["folk-token-mint", "folk-token-ledger", "folk-transaction-builder"],
|
||||
scoping: { defaultScope: 'global', userConfigurable: false },
|
||||
routes,
|
||||
standaloneDomain: "rwallet.online",
|
||||
|
|
|
|||
|
|
@ -1899,7 +1899,7 @@ After creating shapes, give a brief summary of what you placed. Only create shap
|
|||
For text-only questions (explanations, coding help, math), respond with text — don't create shapes unless asked.`;
|
||||
|
||||
app.post("/api/prompt", async (c) => {
|
||||
const { messages, model = "gemini-flash", useTools = false, systemPrompt } = await c.req.json();
|
||||
const { messages, model = "gemini-flash", useTools = false, systemPrompt, enabledModules } = await c.req.json();
|
||||
if (!messages?.length) return c.json({ error: "messages required" }, 400);
|
||||
|
||||
// Determine provider
|
||||
|
|
@ -1912,8 +1912,9 @@ app.post("/api/prompt", async (c) => {
|
|||
// Build model config with optional tools
|
||||
const modelConfig: any = { model: GEMINI_MODELS[model] };
|
||||
if (useTools) {
|
||||
const { CANVAS_TOOL_DECLARATIONS } = await import("../lib/canvas-tools");
|
||||
modelConfig.tools = [{ functionDeclarations: CANVAS_TOOL_DECLARATIONS }];
|
||||
const { getToolsForModules } = await import("../lib/canvas-tools");
|
||||
const tools = getToolsForModules(enabledModules ?? null);
|
||||
modelConfig.tools = [{ functionDeclarations: tools.map(t => t.declaration) }];
|
||||
modelConfig.systemInstruction = systemPrompt || CANVAS_TOOLS_SYSTEM_PROMPT;
|
||||
}
|
||||
const geminiModel = genAI.getGenerativeModel(modelConfig);
|
||||
|
|
|
|||
|
|
@ -173,6 +173,11 @@ export interface RSpaceModule {
|
|||
|
||||
/** Per-module settings schema for space-level configuration */
|
||||
settingsSchema?: ModuleSettingField[];
|
||||
|
||||
/** Canvas shape tag names this module owns (e.g. ["folk-commitment-pool"]) */
|
||||
canvasShapes?: string[];
|
||||
/** Canvas AI tool IDs this module owns (e.g. ["create_commitment_pool"]) */
|
||||
canvasToolIds?: string[];
|
||||
}
|
||||
|
||||
/** Registry of all loaded modules */
|
||||
|
|
@ -210,6 +215,8 @@ export interface ModuleInfo {
|
|||
subPageInfos?: Array<{ path: string; title: string }>;
|
||||
settingsSchema?: ModuleSettingField[];
|
||||
onboardingActions?: OnboardingAction[];
|
||||
canvasShapes?: string[];
|
||||
canvasToolIds?: string[];
|
||||
}
|
||||
|
||||
export function getModuleInfoList(): ModuleInfo[] {
|
||||
|
|
@ -230,5 +237,7 @@ export function getModuleInfoList(): ModuleInfo[] {
|
|||
...(m.subPageInfos ? { subPageInfos: m.subPageInfos.map(s => ({ path: s.path, title: s.title })) } : {}),
|
||||
...(m.settingsSchema ? { settingsSchema: m.settingsSchema } : {}),
|
||||
...(m.onboardingActions ? { onboardingActions: m.onboardingActions } : {}),
|
||||
...(m.canvasShapes ? { canvasShapes: m.canvasShapes } : {}),
|
||||
...(m.canvasToolIds ? { canvasToolIds: m.canvasToolIds } : {}),
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2032,7 +2032,7 @@
|
|||
<button id="new-bookmark" title="Bookmark">🔖 Bookmark</button>
|
||||
<button id="new-google-item" title="Google">📎 Google</button>
|
||||
<button id="new-map" title="Map" data-requires-module="rmaps">🗺️ Map</button>
|
||||
<button id="new-social-post" title="Social Post">📱 Social Post</button>
|
||||
<button id="new-social-post" title="Social Post" data-requires-module="rsocials">📱 Social Post</button>
|
||||
<button id="embed-notes" title="Embed rNotes" data-requires-module="rnotes">📝 rNotes</button>
|
||||
<button id="embed-books" title="Embed rBooks" data-requires-module="rbooks">📚 rBooks</button>
|
||||
<button id="embed-forum" title="Embed rForum" data-requires-module="rforum">💬 rForum</button>
|
||||
|
|
@ -2091,12 +2091,12 @@
|
|||
<button class="toolbar-group-toggle" title="Decide"><span class="tg-icon">📊</span><span class="tg-label">Decide</span></button>
|
||||
<div class="toolbar-dropdown">
|
||||
<div class="toolbar-dropdown-header">Decide</div>
|
||||
<button id="new-choice-vote" title="Poll">☑ Poll</button>
|
||||
<button id="new-choice-rank" title="Ranking">📊 Ranking</button>
|
||||
<button id="new-choice-spider" title="Scoring">🕸 Scoring</button>
|
||||
<button id="new-spider-3d" title="3D Spider">📊 3D Spider</button>
|
||||
<button id="new-conviction" title="Conviction">⏳ Conviction</button>
|
||||
<button id="new-token" title="Token">🪙 Token</button>
|
||||
<button id="new-choice-vote" title="Poll" data-requires-module="rchoices">☑ Poll</button>
|
||||
<button id="new-choice-rank" title="Ranking" data-requires-module="rchoices">📊 Ranking</button>
|
||||
<button id="new-choice-spider" title="Scoring" data-requires-module="rchoices">🕸 Scoring</button>
|
||||
<button id="new-spider-3d" title="3D Spider" data-requires-module="rchoices">📊 3D Spider</button>
|
||||
<button id="new-conviction" title="Conviction" data-requires-module="rchoices">⏳ Conviction</button>
|
||||
<button id="new-token" title="Token" data-requires-module="rwallet">🪙 Token</button>
|
||||
<button id="new-commitment-pool" title="Commitment Pool" data-requires-module="rtime">🧺 Commitments</button>
|
||||
<button id="new-task-request" title="Task Request" data-requires-module="rtime">📋 Task Request</button>
|
||||
<button id="new-multisig-email" title="Multi-Sig Email">✉️ Multi-Sig Email</button>
|
||||
|
|
@ -2111,7 +2111,7 @@
|
|||
<div class="toolbar-dropdown-header">Spend</div>
|
||||
<button id="embed-wallet" title="rWallet" data-requires-module="rwallet">💰 rWallet</button>
|
||||
<button id="embed-flows" title="rFlows" data-requires-module="rflows">🌊 rFlows</button>
|
||||
<button id="new-tx-builder" title="Transaction Builder">🔐 Tx Builder</button>
|
||||
<button id="new-tx-builder" title="Transaction Builder" data-requires-module="rwallet">🔐 Tx Builder</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -2575,6 +2575,15 @@
|
|||
const FolkRApp = customElements.get("folk-rapp");
|
||||
if (FolkRApp?.setEnabledModules) FolkRApp.setEnabledModules(enabledIds);
|
||||
});
|
||||
// Initialize rTime shape disabled states
|
||||
customElements.whenDefined("folk-commitment-pool").then(() => {
|
||||
const cls = customElements.get("folk-commitment-pool");
|
||||
if (cls?.setEnabledModules) cls.setEnabledModules(enabledIds);
|
||||
});
|
||||
customElements.whenDefined("folk-task-request").then(() => {
|
||||
const cls = customElements.get("folk-task-request");
|
||||
if (cls?.setEnabledModules) cls.setEnabledModules(enabledIds);
|
||||
});
|
||||
}).catch(() => {});
|
||||
|
||||
// React to runtime module toggling from app switcher
|
||||
|
|
@ -2591,6 +2600,12 @@
|
|||
const FolkRApp = customElements.get("folk-rapp");
|
||||
if (FolkRApp?.setEnabledModules) FolkRApp.setEnabledModules(enabledModules);
|
||||
|
||||
// Update rTime shape disabled states
|
||||
const FolkCommitmentPool = customElements.get("folk-commitment-pool");
|
||||
if (FolkCommitmentPool?.setEnabledModules) FolkCommitmentPool.setEnabledModules(enabledModules);
|
||||
const FolkTaskRequest = customElements.get("folk-task-request");
|
||||
if (FolkTaskRequest?.setEnabledModules) FolkTaskRequest.setEnabledModules(enabledModules);
|
||||
|
||||
document.querySelectorAll("[data-requires-module]").forEach(el => {
|
||||
el.style.display = enabledSet.has(el.dataset.requiresModule) ? "" : "none";
|
||||
});
|
||||
|
|
@ -2790,6 +2805,13 @@
|
|||
shapeRegistry.register("folk-holon", FolkHolon);
|
||||
shapeRegistry.register("folk-holon-browser", FolkHolonBrowser);
|
||||
|
||||
// Wire shape→module affiliations from module declarations
|
||||
for (const mod of window.__rspaceAllModules || []) {
|
||||
for (const tag of mod.canvasShapes || []) {
|
||||
shapeRegistry.setModule(tag, mod.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Zoom and pan state — declared early to avoid TDZ errors
|
||||
// (event handlers reference these before awaits yield execution)
|
||||
let scale = 1;
|
||||
|
|
|
|||
Loading…
Reference in New Issue