diff --git a/packages/forum_forge/components/ui.json b/packages/forum_forge/components/ui.json new file mode 100644 index 000000000..450aabec3 --- /dev/null +++ b/packages/forum_forge/components/ui.json @@ -0,0 +1,440 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script-components.schema.json", + "schemaVersion": "2.0.0", + "package": "forum_forge", + "description": "Forum Forge UI components including category lists, thread views, and moderation panels", + "components": [ + { + "id": "forum_root", + "name": "ForumRoot", + "description": "Main forum container with hero section, stats, and navigation", + "props": [ + { + "name": "title", + "type": "string", + "required": false, + "default": "Forum Forge", + "description": "Forum title" + }, + { + "name": "subtitle", + "type": "string", + "required": false, + "default": "A modern discussion hub with curated categories, rapid replies, and moderator-ready queues.", + "description": "Forum subtitle" + } + ], + "render": { + "type": "element", + "template": { + "type": "Stack", + "direction": "column", + "gap": 3, + "className": "forum-forge-root", + "children": [ + { + "type": "Card", + "variant": "outlined", + "className": "forum-hero", + "children": [ + { + "type": "Stack", + "direction": "column", + "gap": 2, + "sx": { "p": 3 }, + "children": [ + { + "type": "Text", + "variant": "h4", + "fontWeight": "bold", + "children": "{{title}}" + }, + { + "type": "Text", + "variant": "body1", + "color": "secondary", + "children": "{{subtitle}}" + }, + { + "type": "Flex", + "gap": 1, + "children": [ + { + "type": "Button", + "variant": "contained", + "color": "primary", + "children": "Start new thread" + }, + { + "type": "Button", + "variant": "outlined", + "children": "Browse categories" + } + ] + } + ] + } + ] + } + ] + } + } + }, + { + "id": "forum_stat_card", + "name": "ForumStatCard", + "description": "Stat card for forum metrics (active threads, replies, flags)", + "props": [ + { + "name": "label", + "type": "string", + "required": true, + "description": "Stat label" + }, + { + "name": "value", + "type": "string", + "required": true, + "description": "Stat value" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "forum-stat-card", + "children": [ + { + "type": "Stack", + "direction": "column", + "gap": 0.5, + "sx": { "p": 2 }, + "children": [ + { + "type": "Text", + "variant": "caption", + "color": "secondary", + "children": "{{label}}" + }, + { + "type": "Text", + "variant": "h5", + "fontWeight": "semibold", + "children": "{{value}}" + } + ] + } + ] + } + } + }, + { + "id": "forum_stats_grid", + "name": "ForumStatsGrid", + "description": "Grid layout for forum statistics", + "props": [ + { + "name": "activeThreads", + "type": "string", + "default": "246" + }, + { + "name": "repliesToday", + "type": "string", + "default": "1,092" + }, + { + "name": "queuedFlags", + "type": "string", + "default": "8" + } + ], + "render": { + "type": "element", + "template": { + "type": "Grid", + "container": true, + "spacing": 2, + "className": "forum-stats-grid", + "children": [ + { + "type": "Grid", + "item": true, + "xs": 12, + "sm": 4, + "children": [ + { + "type": "ForumStatCard", + "label": "Active threads", + "value": "{{activeThreads}}" + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 12, + "sm": 4, + "children": [ + { + "type": "ForumStatCard", + "label": "Replies today", + "value": "{{repliesToday}}" + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 12, + "sm": 4, + "children": [ + { + "type": "ForumStatCard", + "label": "Queued flags", + "value": "{{queuedFlags}}" + } + ] + } + ] + } + } + }, + { + "id": "category_card", + "name": "CategoryCard", + "description": "Card displaying a forum category with title and description", + "props": [ + { + "name": "title", + "type": "string", + "required": true, + "description": "Category title" + }, + { + "name": "description", + "type": "string", + "required": true, + "description": "Category description" + }, + { + "name": "onClick", + "type": "function", + "required": false, + "description": "Click handler" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "forum-category-card", + "onClick": "{{onClick}}", + "children": [ + { + "type": "Stack", + "direction": "column", + "gap": 0.5, + "sx": { "p": 2 }, + "children": [ + { + "type": "Text", + "variant": "h6", + "fontWeight": "semibold", + "children": "{{title}}" + }, + { + "type": "Text", + "variant": "body2", + "color": "secondary", + "children": "{{description}}" + } + ] + } + ] + } + } + }, + { + "id": "category_list", + "name": "CategoryList", + "description": "List of forum categories", + "props": [ + { + "name": "categories", + "type": "array", + "required": false, + "default": [], + "description": "Array of category objects" + }, + { + "name": "title", + "type": "string", + "default": "Featured categories" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "forum-categories", + "children": [ + { + "type": "Stack", + "direction": "column", + "gap": 2, + "sx": { "p": 3 }, + "children": [ + { + "type": "Text", + "variant": "h5", + "fontWeight": "semibold", + "children": "{{title}}" + }, + { + "type": "Stack", + "direction": "column", + "gap": 1.5, + "children": { + "type": "loop", + "items": "{{categories}}", + "itemKey": "id", + "template": { + "type": "CategoryCard", + "title": "{{item.title}}", + "description": "{{item.description}}" + } + } + } + ] + } + ] + } + } + }, + { + "id": "thread_card", + "name": "ThreadCard", + "description": "Card displaying a forum thread with title and metadata", + "props": [ + { + "name": "title", + "type": "string", + "required": true, + "description": "Thread title" + }, + { + "name": "replyCount", + "type": "number", + "required": false, + "default": 0, + "description": "Number of replies" + }, + { + "name": "lastUpdated", + "type": "string", + "required": false, + "description": "Last update time" + }, + { + "name": "onClick", + "type": "function", + "required": false + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "forum-thread-card", + "onClick": "{{onClick}}", + "children": [ + { + "type": "Stack", + "direction": "column", + "gap": 0.5, + "sx": { "p": 2 }, + "children": [ + { + "type": "Text", + "variant": "subtitle1", + "fontWeight": "semibold", + "children": "{{title}}" + }, + { + "type": "Text", + "variant": "caption", + "color": "secondary", + "children": "{{replyCount}} replies ยท Updated {{lastUpdated}}" + } + ] + } + ] + } + } + }, + { + "id": "thread_list", + "name": "ThreadList", + "description": "List of forum threads", + "props": [ + { + "name": "threads", + "type": "array", + "required": false, + "default": [], + "description": "Array of thread objects" + }, + { + "name": "title", + "type": "string", + "default": "Trending threads" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "forum-threads", + "children": [ + { + "type": "Stack", + "direction": "column", + "gap": 2, + "sx": { "p": 3 }, + "children": [ + { + "type": "Text", + "variant": "h5", + "fontWeight": "semibold", + "children": "{{title}}" + }, + { + "type": "Stack", + "direction": "column", + "gap": 1.5, + "children": { + "type": "loop", + "items": "{{threads}}", + "itemKey": "id", + "template": { + "type": "ThreadCard", + "title": "{{item.title}}", + "replyCount": "{{item.replyCount}}", + "lastUpdated": "{{item.lastUpdated}}" + } + } + } + ] + } + ] + } + } + } + ] +} diff --git a/packages/forum_forge/package.json b/packages/forum_forge/package.json new file mode 100644 index 000000000..2b45dd1f9 --- /dev/null +++ b/packages/forum_forge/package.json @@ -0,0 +1,62 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-metadata.schema.json", + "packageId": "forum_forge", + "name": "Forum Forge", + "version": "1.0.0", + "description": "Modern forum starter with categories, threads, and moderation lanes", + "author": "MetaBuilder", + "license": "MIT", + "category": "social", + "minLevel": 2, + "primary": true, + "icon": "static_content/icon.svg", + "keywords": ["forum", "discussion", "threads", "moderation", "community"], + "dependencies": { + "ui_permissions": "^1.0.0", + "data_table": "^1.0.0", + "form_builder": "^1.0.0" + }, + "devDependencies": { + "lua_test": "^1.0.0" + }, + "exports": { + "components": [ + "ForumRoot", + "CategoryList", + "ThreadList", + "ThreadCard", + "StatCard" + ], + "scripts": [ + "create_thread", + "view_categories", + "thread_list", + "init", + "permissions", + "thread_rank", + "moderation" + ] + }, + "tests": { + "scripts": [ + "tests/metadata.test.lua", + "tests/components.test.lua" + ], + "parameterized": [ + { + "parameters": "tests/metadata.cases.json" + }, + { + "parameters": "tests/components.cases.json" + } + ] + }, + "schema": { + "entities": [ + "ForumCategory", + "ForumThread", + "ForumPost" + ], + "path": "schema/entities.yaml" + } +} diff --git a/packages/forum_forge/permissions/roles.json b/packages/forum_forge/permissions/roles.json new file mode 100644 index 000000000..0706b04ac --- /dev/null +++ b/packages/forum_forge/permissions/roles.json @@ -0,0 +1,121 @@ +{ + "$schema": "https://metabuilder.dev/schemas/permissions.schema.json", + "schemaVersion": "1.0.0", + "package": "forum_forge", + "description": "Forum Forge access permissions for posting, viewing, and moderation", + "permissions": [ + { + "id": "forum.view", + "name": "View Forum", + "description": "View forum categories and threads", + "resource": "forum", + "action": "read", + "scope": "global", + "minLevel": 2 + }, + { + "id": "forum.thread.create", + "name": "Create Thread", + "description": "Create new forum threads", + "resource": "forum.thread", + "action": "create", + "scope": "global", + "minLevel": 2 + }, + { + "id": "forum.post.create", + "name": "Create Post", + "description": "Create posts/replies in forum threads", + "resource": "forum.post", + "action": "create", + "scope": "global", + "minLevel": 2 + }, + { + "id": "forum.moderate", + "name": "Moderate Forum", + "description": "Moderate forum content including flagging, editing, and removing posts", + "resource": "forum", + "action": "moderate", + "scope": "global", + "minLevel": 3 + }, + { + "id": "forum.category.manage", + "name": "Manage Categories", + "description": "Create, edit, and delete forum categories", + "resource": "forum.category", + "action": "manage", + "scope": "global", + "minLevel": 4 + } + ], + "resources": [ + { + "id": "forum", + "name": "Forum", + "type": "content", + "description": "Forum resources including categories, threads, and posts", + "actions": ["read", "moderate"] + }, + { + "id": "forum.thread", + "name": "Forum Thread", + "type": "content", + "description": "Forum thread resources", + "actions": ["create", "read", "update", "delete"] + }, + { + "id": "forum.post", + "name": "Forum Post", + "type": "content", + "description": "Forum post/reply resources", + "actions": ["create", "read", "update", "delete"] + }, + { + "id": "forum.category", + "name": "Forum Category", + "type": "config", + "description": "Forum category configuration", + "actions": ["manage", "read"] + } + ], + "roles": [ + { + "id": "forum.user", + "name": "Forum User", + "description": "Standard forum user who can view and post", + "minLevel": 2, + "permissions": [ + "forum.view", + "forum.thread.create", + "forum.post.create" + ] + }, + { + "id": "forum.moderator", + "name": "Forum Moderator", + "description": "Forum moderator who can manage content", + "minLevel": 3, + "permissions": [ + "forum.view", + "forum.thread.create", + "forum.post.create", + "forum.moderate" + ] + }, + { + "id": "forum.admin", + "name": "Forum Administrator", + "description": "Forum administrator with full access", + "minLevel": 4, + "permissions": [ + "forum.view", + "forum.thread.create", + "forum.post.create", + "forum.moderate", + "forum.category.manage" + ] + } + ] +} diff --git a/packages/forum_forge/scripts/functions.json b/packages/forum_forge/scripts/functions.json new file mode 100644 index 000000000..c23ee1d16 --- /dev/null +++ b/packages/forum_forge/scripts/functions.json @@ -0,0 +1,102 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script.schema.json", + "schemaVersion": "2.2.0", + "package": "forum_forge", + "description": "Forum Forge script functions for thread management, permissions, ranking, and moderation", + "functions": [ + { + "id": "forum_init", + "name": "init", + "exported": true, + "description": "Initialize Forum Forge package", + "category": "lifecycle", + "luaScript": "init.lua" + }, + { + "id": "forum_on_install", + "name": "onInstall", + "exported": true, + "description": "Package installation hook", + "category": "lifecycle", + "luaScript": "init.lua" + }, + { + "id": "forum_on_uninstall", + "name": "onUninstall", + "exported": true, + "description": "Package uninstallation hook", + "category": "lifecycle", + "luaScript": "init.lua" + }, + { + "id": "forum_can_post", + "name": "canPost", + "exported": true, + "description": "Check if user has permission to post in forum", + "category": "permissions", + "luaScript": "permissions.lua" + }, + { + "id": "forum_can_moderate", + "name": "canModerate", + "exported": true, + "description": "Check if user has permission to moderate forum", + "category": "permissions", + "luaScript": "permissions.lua" + }, + { + "id": "forum_rank_thread", + "name": "rankThread", + "exported": true, + "description": "Calculate thread ranking score based on recency and engagement", + "category": "ranking", + "luaScript": "thread_rank.lua" + }, + { + "id": "forum_flag_post", + "name": "flagPost", + "exported": true, + "description": "Flag a post for moderation review", + "category": "moderation", + "luaScript": "moderation.lua" + }, + { + "id": "forum_create_thread", + "name": "createThread", + "exported": true, + "description": "Create a new forum thread", + "category": "threads", + "luaScript": "threads.lua" + }, + { + "id": "forum_view_categories", + "name": "viewCategories", + "exported": true, + "description": "Retrieve and render forum categories", + "category": "categories", + "luaScript": "categories.lua" + }, + { + "id": "forum_thread_list", + "name": "threadList", + "exported": true, + "description": "Retrieve and render thread list", + "category": "threads", + "luaScript": "threads.lua" + } + ], + "exports": { + "functions": [ + "init", + "onInstall", + "onUninstall", + "canPost", + "canModerate", + "rankThread", + "flagPost", + "createThread", + "viewCategories", + "threadList" + ] + } +} diff --git a/packages/forum_forge/storybook/stories.json b/packages/forum_forge/storybook/stories.json new file mode 100644 index 000000000..cf42280dc --- /dev/null +++ b/packages/forum_forge/storybook/stories.json @@ -0,0 +1,160 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-storybook.schema.json", + "featured": true, + "title": "Forum Forge Components", + "description": "Modern forum UI with categories, threads, and moderation", + "stories": [ + { + "name": "CreateThread", + "render": "create_thread", + "description": "Thread creation form with category selection and rich text editor", + "args": { + "categoryId": "launch-radar", + "title": "", + "content": "" + } + }, + { + "name": "ViewCategories", + "render": "view_categories", + "description": "Browse all forum categories", + "args": { + "categories": [ + { + "id": "launch-radar", + "title": "Launch Radar", + "description": "Share product launches, traction stories, and founder notes." + }, + { + "id": "growth-ops", + "title": "Growth Ops", + "description": "Tactics for onboarding, retention, and community rituals." + }, + { + "id": "dev-lounge", + "title": "Dev Lounge", + "description": "Deep dives on tooling, architecture, and deployment patterns." + } + ] + } + }, + { + "name": "ThreadList", + "render": "thread_list", + "description": "View trending threads with engagement metrics", + "args": { + "threads": [ + { + "id": "thread-1", + "title": "What does your onboarding checklist look like in 2025?", + "replyCount": 128, + "lastUpdated": "2h ago" + }, + { + "id": "thread-2", + "title": "Best practices for AI-assisted moderation?", + "replyCount": 64, + "lastUpdated": "30m ago" + } + ] + } + }, + { + "name": "ForumStats", + "render": "stats", + "description": "Forum statistics dashboard", + "args": { + "activeThreads": "246", + "repliesToday": "1,092", + "queuedFlags": "8" + } + }, + { + "name": "ModerationQueue", + "render": "moderation_queue", + "description": "Moderation queue for flagged content", + "type": "function", + "args": { + "flags": [] + } + } + ], + "renders": { + "create_thread": { + "description": "Thread creation form", + "featured": true + }, + "view_categories": { + "description": "Category browser", + "featured": true + }, + "thread_list": { + "description": "Trending threads list", + "featured": true + }, + "stats": { + "description": "Forum statistics overview" + }, + "moderation_queue": { + "description": "Moderation queue for flagged posts" + } + }, + "defaultContext": { + "user": { + "id": "demo-user", + "username": "demo_user", + "level": 2, + "email": "demo@example.com" + }, + "tenant": { + "id": "demo-tenant", + "name": "Demo Organization" + } + }, + "contextVariants": [ + { + "name": "Standard User", + "description": "Can view and post in forums", + "context": { + "user": { + "username": "user", + "level": 2 + } + } + }, + { + "name": "Moderator", + "description": "Can view, post, and moderate forums", + "context": { + "user": { + "username": "moderator", + "level": 3 + } + } + }, + { + "name": "Admin", + "description": "Full forum access including category management", + "context": { + "user": { + "username": "admin", + "level": 4 + } + } + } + ], + "scripts": { + "renderFunctions": ["create_thread", "view_categories", "thread_list", "stats", "moderation_queue"], + "ignoredScripts": ["tests"] + }, + "parameters": { + "layout": "padded", + "backgrounds": { + "default": "light", + "values": [ + { "name": "light", "value": "#f5f5f5" }, + { "name": "dark", "value": "#1a1a1a" } + ] + } + } +} diff --git a/packages/forum_forge/styles/tokens.json b/packages/forum_forge/styles/tokens.json new file mode 100644 index 000000000..01028e9a9 --- /dev/null +++ b/packages/forum_forge/styles/tokens.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-styles.schema.json", + "schemaVersion": "2.0.0", + "package": "forum_forge", + "description": "Design tokens for Forum Forge components", + "colors": { + "categoryPrimary": "#3b82f6", + "categorySecondary": "#8b5cf6", + "threadActive": "#22c55e", + "threadPinned": "#f59e0b", + "flagWarning": "#ef4444", + "flagPending": "#f97316", + "moderatorBadge": "#6366f1", + "replyHighlight": "#dbeafe", + "statPositive": "#28a745", + "statNegative": "#dc3545", + "statNeutral": "#6c757d" + }, + "spacing": { + "cardPadding": "16px", + "sectionGap": "24px", + "listItemGap": "12px", + "statsGrid": "16px", + "heroSection": "24px" + }, + "shadows": { + "card": "0 2px 8px rgba(0, 0, 0, 0.1)", + "cardHover": "0 4px 16px rgba(0, 0, 0, 0.15)", + "statCard": "0 1px 4px rgba(0, 0, 0, 0.08)", + "categoryCard": "0 2px 6px rgba(0, 0, 0, 0.08)" + }, + "borders": { + "cardRadius": "8px", + "buttonRadius": "6px", + "badgeRadius": "4px", + "defaultBorder": "1px solid #e5e7eb" + }, + "typography": { + "heroTitle": { + "fontSize": "1.5rem", + "fontWeight": 700, + "lineHeight": 1.3 + }, + "sectionTitle": { + "fontSize": "1.25rem", + "fontWeight": 600, + "lineHeight": 1.4 + }, + "threadTitle": { + "fontSize": "1.125rem", + "fontWeight": 600, + "lineHeight": 1.4 + }, + "statValue": { + "fontSize": "1.25rem", + "fontWeight": 600, + "lineHeight": 1.2 + }, + "statLabel": { + "fontSize": "0.875rem", + "fontWeight": 400, + "lineHeight": 1.5 + }, + "meta": { + "fontSize": "0.75rem", + "fontWeight": 400, + "lineHeight": 1.5 + } + } +} diff --git a/packages/github_tools/components/ui.json b/packages/github_tools/components/ui.json new file mode 100644 index 000000000..661b44bc0 --- /dev/null +++ b/packages/github_tools/components/ui.json @@ -0,0 +1,527 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script-components.schema.json", + "schemaVersion": "2.0.0", + "package": "github_tools", + "description": "GitHub Tools components for Actions viewer, run analysis, and workflow management", + "components": [ + { + "id": "github_viewer", + "name": "GitHubViewer", + "description": "Main GitHub Actions viewer component", + "props": [ + { + "name": "owner", + "type": "string", + "required": true, + "description": "Repository owner" + }, + { + "name": "repo", + "type": "string", + "required": true, + "description": "Repository name" + }, + { + "name": "workflow", + "type": "string", + "required": false, + "description": "Workflow file name filter" + }, + { + "name": "token", + "type": "string", + "required": false, + "description": "GitHub API token" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "github-viewer", + "children": [ + { + "type": "CardHeader", + "title": "GitHub Actions", + "subtitle": "{{owner}}/{{repo}}" + }, + { + "type": "CardContent", + "children": [ + { + "type": "RunFilters", + "props": {} + }, + { + "type": "RunList", + "props": {} + } + ] + } + ] + } + }, + "scripts": { + "init": "init.initialize", + "fetchRuns": "fetch_runs.fetchRuns", + "filterRuns": "filter.filterRuns" + } + }, + { + "id": "run_list", + "name": "RunList", + "description": "List of workflow runs with status badges", + "props": [ + { + "name": "runs", + "type": "array", + "required": false, + "default": [], + "description": "Array of workflow runs" + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": false, + "description": "Loading state indicator" + }, + { + "name": "onSelect", + "type": "function", + "required": false, + "description": "Callback when a run is selected" + } + ], + "render": { + "type": "element", + "template": { + "type": "Stack", + "spacing": 2, + "className": "run-list", + "children": [ + { + "type": "conditional", + "condition": "{{loading}}", + "then": { + "type": "Box", + "sx": { "display": "flex", "justifyContent": "center", "p": 4 }, + "children": [ + { + "type": "CircularProgress" + } + ] + }, + "else": { + "type": "iterate", + "items": "{{runs}}", + "render": { + "type": "Card", + "variant": "outlined", + "sx": { "cursor": "pointer" }, + "onClick": "{{onSelect}}", + "children": [ + { + "type": "CardContent", + "children": [ + { + "type": "Flex", + "justifyContent": "space-between", + "alignItems": "center", + "children": [ + { + "type": "Text", + "variant": "subtitle1", + "children": "{{item.name}}" + }, + { + "type": "StatusBadge", + "status": "{{item.conclusion || item.status}}" + } + ] + } + ] + } + ] + } + } + } + ] + } + } + }, + { + "id": "run_details", + "name": "RunDetails", + "description": "Detailed view of a single workflow run", + "props": [ + { + "name": "run", + "type": "object", + "required": false, + "description": "Selected workflow run" + }, + { + "name": "jobs", + "type": "array", + "required": false, + "default": [], + "description": "Array of jobs for the run" + }, + { + "name": "logs", + "type": "string", + "required": false, + "default": "", + "description": "Log content" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "run-details", + "children": [ + { + "type": "CardHeader", + "title": "Run Details", + "subtitle": "{{run.name}}" + }, + { + "type": "CardContent", + "children": [ + { + "type": "Stack", + "spacing": 2, + "children": [ + { + "type": "StatusBadge", + "status": "{{run.conclusion || run.status}}" + }, + { + "type": "Divider" + }, + { + "type": "Text", + "variant": "subtitle2", + "children": "Jobs" + }, + { + "type": "iterate", + "items": "{{jobs}}", + "render": { + "type": "Flex", + "alignItems": "center", + "gap": 1, + "children": [ + { + "type": "StatusBadge", + "status": "{{item.conclusion || item.status}}" + }, + { + "type": "Text", + "children": "{{item.name}}" + } + ] + } + }, + { + "type": "conditional", + "condition": "{{logs}}", + "then": { + "type": "Box", + "children": [ + { + "type": "Text", + "variant": "subtitle2", + "children": "Logs" + }, + { + "type": "Paper", + "variant": "outlined", + "sx": { + "p": 2, + "fontFamily": "monospace", + "fontSize": "0.875rem", + "maxHeight": 400, + "overflow": "auto", + "backgroundColor": "#1e1e1e", + "color": "#d4d4d4" + }, + "children": "{{logs}}" + } + ] + } + } + ] + } + ] + } + ] + } + } + }, + { + "id": "analysis_panel", + "name": "AnalysisPanel", + "description": "Statistics and analysis of workflow runs", + "props": [ + { + "name": "stats", + "type": "object", + "required": false, + "default": {}, + "description": "Statistics object" + }, + { + "name": "timeRange", + "type": "string", + "required": false, + "default": "7d", + "description": "Time range for analysis" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "analysis-panel", + "children": [ + { + "type": "CardHeader", + "title": "Run Analysis" + }, + { + "type": "CardContent", + "children": [ + { + "type": "Grid", + "container": true, + "spacing": 2, + "children": [ + { + "type": "Grid", + "item": true, + "xs": 6, + "md": 3, + "children": [ + { + "type": "StatCard", + "label": "Total Runs", + "value": "{{stats.total || 0}}", + "icon": "PlayArrow", + "color": "primary" + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 6, + "md": 3, + "children": [ + { + "type": "StatCard", + "label": "Success", + "value": "{{stats.success || 0}}", + "icon": "CheckCircle", + "color": "success" + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 6, + "md": 3, + "children": [ + { + "type": "StatCard", + "label": "Failures", + "value": "{{stats.failure || 0}}", + "icon": "Cancel", + "color": "error" + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 6, + "md": 3, + "children": [ + { + "type": "StatCard", + "label": "Success Rate", + "value": "{{stats.success_rate || 0}}%", + "icon": "TrendingUp", + "color": "info" + } + ] + } + ] + } + ] + } + ] + } + }, + "scripts": { + "calculate": "analyze.calculateStats" + } + }, + { + "id": "run_filters", + "name": "RunFilters", + "description": "Filter controls for workflow runs", + "props": [ + { + "name": "status", + "type": "string", + "required": false, + "default": "all", + "description": "Status filter value" + }, + { + "name": "branch", + "type": "string", + "required": false, + "default": "", + "description": "Branch filter value" + }, + { + "name": "dateRange", + "type": "string", + "required": false, + "default": "7d", + "description": "Date range filter value" + }, + { + "name": "onChange", + "type": "function", + "required": false, + "description": "Callback when filters change" + } + ], + "render": { + "type": "element", + "template": { + "type": "Stack", + "direction": "row", + "spacing": 2, + "className": "run-filters", + "sx": { "mb": 2 }, + "children": [ + { + "type": "FormControl", + "size": "small", + "sx": { "minWidth": 120 }, + "children": [ + { + "type": "InputLabel", + "children": "Status" + }, + { + "type": "Select", + "label": "Status", + "name": "status", + "value": "{{status}}", + "onChange": "{{onChange}}", + "options": [ + { "value": "all", "label": "All" }, + { "value": "success", "label": "Success" }, + { "value": "failure", "label": "Failure" }, + { "value": "pending", "label": "Pending" } + ] + } + ] + }, + { + "type": "TextField", + "label": "Branch", + "name": "branch", + "size": "small", + "value": "{{branch}}", + "onChange": "{{onChange}}", + "placeholder": "main" + }, + { + "type": "FormControl", + "size": "small", + "sx": { "minWidth": 140 }, + "children": [ + { + "type": "InputLabel", + "children": "Time Range" + }, + { + "type": "Select", + "label": "Time Range", + "name": "dateRange", + "value": "{{dateRange}}", + "onChange": "{{onChange}}", + "options": [ + { "value": "1d", "label": "Last 24 hours" }, + { "value": "7d", "label": "Last 7 days" }, + { "value": "30d", "label": "Last 30 days" } + ] + } + ] + } + ] + } + }, + "scripts": { + "onChange": "filter.applyFilters" + } + }, + { + "id": "status_badge", + "name": "StatusBadge", + "description": "Status badge showing run conclusion with appropriate color and icon", + "props": [ + { + "name": "status", + "type": "string", + "required": true, + "description": "Run status (success, failure, pending, in_progress, cancelled, skipped)" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "small", + "description": "Badge size" + } + ], + "render": { + "type": "element", + "template": { + "type": "Chip", + "label": "{{status | statusLabel}}", + "color": "{{status | statusColor}}", + "size": "{{size}}", + "icon": "{{status | statusIcon}}" + } + }, + "scripts": { + "statusLabel": "status.getStatusLabel", + "statusColor": "status.getStatusColor", + "statusIcon": "status.getStatusIcon" + } + } + ], + "exports": { + "components": [ + "GitHubViewer", + "RunList", + "RunDetails", + "AnalysisPanel", + "RunFilters", + "StatusBadge" + ] + } +} diff --git a/packages/github_tools/package.json b/packages/github_tools/package.json new file mode 100644 index 000000000..ededf4f02 --- /dev/null +++ b/packages/github_tools/package.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-metadata.schema.json", + "packageId": "github_tools", + "name": "GitHub Tools", + "version": "1.0.0", + "description": "GitHub integration tools including Actions viewer, run analysis, and workflow management", + "author": "MetaBuilder", + "license": "MIT", + "category": "development", + "minLevel": 2, + "primary": true, + "tags": [ + "github", + "ci-cd", + "workflow", + "actions" + ], + "dependencies": {}, + "devDependencies": { + "lua_test": "*" + }, + "exports": { + "components": [ + "GitHubViewer", + "RunList", + "RunDetails", + "AnalysisPanel", + "RunFilters" + ], + "scripts": [ + "fetch_runs", + "analyze", + "filter", + "status" + ] + }, + "tests": { + "scripts": [ + "tests/metadata.test.lua" + ], + "parameterized": [ + { + "parameters": "tests/metadata.cases.json" + } + ] + } +} diff --git a/packages/github_tools/permissions/roles.json b/packages/github_tools/permissions/roles.json new file mode 100644 index 000000000..b4d30150b --- /dev/null +++ b/packages/github_tools/permissions/roles.json @@ -0,0 +1,83 @@ +{ + "$schema": "https://metabuilder.dev/schemas/permissions.schema.json", + "schemaVersion": "1.0.0", + "package": "github_tools", + "description": "GitHub Tools access permissions", + "permissions": [ + { + "id": "github.runs.view", + "name": "View GitHub Actions Runs", + "description": "View GitHub Actions workflow runs", + "resource": "github_runs", + "action": "read", + "scope": "global", + "minLevel": 2 + }, + { + "id": "github.runs.analyze", + "name": "Analyze GitHub Actions Runs", + "description": "Analyze GitHub Actions run statistics", + "resource": "github_runs", + "action": "analyze", + "scope": "global", + "minLevel": 2 + }, + { + "id": "github.workflow.trigger", + "name": "Trigger Workflow Runs", + "description": "Trigger new GitHub Actions workflow runs", + "resource": "github_workflow", + "action": "execute", + "scope": "global", + "minLevel": 3 + }, + { + "id": "github.logs.view", + "name": "View Workflow Logs", + "description": "View job logs from workflow runs", + "resource": "github_logs", + "action": "read", + "scope": "global", + "minLevel": 2 + }, + { + "id": "github.config.manage", + "name": "Manage GitHub Configuration", + "description": "Configure GitHub repository settings and tokens", + "resource": "github_config", + "action": "write", + "scope": "global", + "minLevel": 3 + } + ], + "resources": [ + { + "id": "github_runs", + "name": "GitHub Workflow Runs", + "type": "external", + "description": "GitHub Actions workflow runs", + "actions": ["read", "analyze"] + }, + { + "id": "github_workflow", + "name": "GitHub Workflows", + "type": "external", + "description": "GitHub Actions workflow definitions", + "actions": ["read", "execute"] + }, + { + "id": "github_logs", + "name": "GitHub Job Logs", + "type": "external", + "description": "GitHub Actions job logs", + "actions": ["read"] + }, + { + "id": "github_config", + "name": "GitHub Configuration", + "type": "config", + "description": "GitHub integration configuration", + "actions": ["read", "write"] + } + ] +} diff --git a/packages/github_tools/scripts/functions.json b/packages/github_tools/scripts/functions.json new file mode 100644 index 000000000..373131f68 --- /dev/null +++ b/packages/github_tools/scripts/functions.json @@ -0,0 +1,156 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script.schema.json", + "schemaVersion": "2.2.0", + "package": "github_tools", + "description": "GitHub Tools functions for fetching runs, analyzing data, and filtering results", + "functions": [ + { + "id": "init_initialize", + "name": "initialize", + "exported": true, + "description": "Initialize the GitHub Tools package with configuration", + "category": "initialization", + "luaScript": "init.lua" + }, + { + "id": "fetch_runs_fetchRuns", + "name": "fetchRuns", + "exported": true, + "description": "Fetch workflow runs from GitHub API", + "category": "api", + "luaScript": "fetch_runs.lua" + }, + { + "id": "fetch_runs_fetchJobs", + "name": "fetchJobs", + "exported": true, + "description": "Fetch jobs for a specific workflow run", + "category": "api", + "luaScript": "fetch_runs.lua" + }, + { + "id": "fetch_runs_fetchLogs", + "name": "fetchLogs", + "exported": true, + "description": "Fetch logs for a specific job", + "category": "api", + "luaScript": "fetch_runs.lua" + }, + { + "id": "analyze_calculateStats", + "name": "calculateStats", + "exported": true, + "description": "Calculate statistics from workflow runs", + "category": "analytics", + "luaScript": "analyze.lua" + }, + { + "id": "analyze_getSuccessTrend", + "name": "getSuccessTrend", + "exported": true, + "description": "Get trend data for success rate over time", + "category": "analytics", + "luaScript": "analyze.lua" + }, + { + "id": "analyze_getFailureBreakdown", + "name": "getFailureBreakdown", + "exported": true, + "description": "Get failure breakdown by type", + "category": "analytics", + "luaScript": "analyze.lua" + }, + { + "id": "filter_filterRuns", + "name": "filterRuns", + "exported": true, + "description": "Apply filters to workflow runs", + "category": "filtering", + "luaScript": "filter.lua" + }, + { + "id": "filter_applyFilters", + "name": "applyFilters", + "exported": true, + "description": "Apply filters from form data", + "category": "filtering", + "luaScript": "filter.lua" + }, + { + "id": "filter_sortRuns", + "name": "sortRuns", + "exported": true, + "description": "Sort runs by field", + "category": "filtering", + "luaScript": "filter.lua" + }, + { + "id": "status_getStatusColor", + "name": "getStatusColor", + "exported": true, + "description": "Get color for run status", + "category": "display", + "luaScript": "status.lua" + }, + { + "id": "status_getStatusIcon", + "name": "getStatusIcon", + "exported": true, + "description": "Get icon name for run status", + "category": "display", + "luaScript": "status.lua" + }, + { + "id": "status_getStatusLabel", + "name": "getStatusLabel", + "exported": true, + "description": "Get human-readable status label", + "category": "display", + "luaScript": "status.lua" + }, + { + "id": "status_renderBadge", + "name": "renderBadge", + "exported": true, + "description": "Render status badge component", + "category": "display", + "luaScript": "status.lua" + }, + { + "id": "status_formatDuration", + "name": "formatDuration", + "exported": true, + "description": "Format duration in human-readable form", + "category": "display", + "luaScript": "status.lua" + }, + { + "id": "status_formatRelativeTime", + "name": "formatRelativeTime", + "exported": true, + "description": "Format timestamp as relative time", + "category": "display", + "luaScript": "status.lua" + } + ], + "exports": { + "functions": [ + "initialize", + "fetchRuns", + "fetchJobs", + "fetchLogs", + "calculateStats", + "getSuccessTrend", + "getFailureBreakdown", + "filterRuns", + "applyFilters", + "sortRuns", + "getStatusColor", + "getStatusIcon", + "getStatusLabel", + "renderBadge", + "formatDuration", + "formatRelativeTime" + ] + } +} diff --git a/packages/github_tools/storybook/config.json b/packages/github_tools/storybook/config.json new file mode 100644 index 000000000..d320eaf78 --- /dev/null +++ b/packages/github_tools/storybook/config.json @@ -0,0 +1,172 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-storybook.schema.json", + "featured": true, + "title": "GitHub Tools", + "description": "GitHub Actions viewer, run analysis, and workflow management components", + "stories": [ + { + "name": "GitHubViewer", + "render": "fetch_runs", + "description": "Main GitHub Actions viewer with runs list and filters", + "args": { + "owner": "metabuilder-dev", + "repo": "metabuilder", + "workflow": "", + "token": "" + } + }, + { + "name": "RunListWithData", + "render": "fetch_runs", + "description": "Run list populated with sample workflow runs", + "args": { + "runs": [ + { + "id": 1, + "name": "CI Pipeline", + "status": "completed", + "conclusion": "success", + "head_branch": "main", + "created_at": "2026-01-02T10:00:00Z" + }, + { + "id": 2, + "name": "CI Pipeline", + "status": "completed", + "conclusion": "failure", + "head_branch": "feature/new-ui", + "created_at": "2026-01-02T09:30:00Z" + }, + { + "id": 3, + "name": "Deploy Preview", + "status": "in_progress", + "conclusion": null, + "head_branch": "main", + "created_at": "2026-01-02T10:15:00Z" + } + ], + "loading": false + } + }, + { + "name": "AnalysisPanel", + "render": "analyze", + "description": "Statistics and analysis dashboard", + "args": { + "stats": { + "total": 150, + "success": 120, + "failure": 25, + "pending": 5, + "success_rate": 80.0, + "avg_duration": 245 + }, + "timeRange": "7d" + } + }, + { + "name": "RunDetails", + "render": "status", + "description": "Detailed view of a single workflow run", + "args": { + "run": { + "id": 1, + "name": "CI Pipeline", + "status": "completed", + "conclusion": "success", + "head_branch": "main" + }, + "jobs": [ + { "id": 1, "name": "Build", "status": "completed", "conclusion": "success" }, + { "id": 2, "name": "Test", "status": "completed", "conclusion": "success" }, + { "id": 3, "name": "Deploy", "status": "completed", "conclusion": "success" } + ], + "logs": "Running build...\nBuild completed successfully.\nRunning tests...\nAll tests passed." + } + }, + { + "name": "StatusBadges", + "render": "status", + "description": "All status badge variants", + "type": "function" + } + ], + "renders": { + "fetch_runs": { + "description": "Main viewer with run fetching functionality", + "featured": true + }, + "analyze": { + "description": "Analysis panel with statistics" + }, + "filter": { + "description": "Filter controls for runs" + }, + "status": { + "description": "Status badge and formatting utilities" + } + }, + "defaultContext": { + "user": { + "id": "demo-user", + "username": "demo_user", + "level": 2, + "email": "demo@example.com" + }, + "tenant": { + "id": "demo-tenant", + "name": "Demo Organization" + }, + "config": { + "owner": "metabuilder-dev", + "repo": "metabuilder" + } + }, + "contextVariants": [ + { + "name": "Standard User", + "description": "Can view runs and analyze statistics", + "context": { + "user": { + "username": "user", + "level": 2 + } + } + }, + { + "name": "Admin", + "description": "Can view, analyze, and trigger workflows", + "context": { + "user": { + "username": "admin", + "level": 3 + } + } + }, + { + "name": "Read Only", + "description": "Public read-only access", + "context": { + "user": { + "username": "guest", + "level": 1 + } + } + } + ], + "scripts": { + "renderFunctions": ["fetch_runs", "analyze", "filter", "status"], + "ignoredScripts": ["tests", "init", "types", "db"] + }, + "parameters": { + "layout": "padded", + "backgrounds": { + "default": "light", + "values": [ + { "name": "light", "value": "#f5f5f5" }, + { "name": "dark", "value": "#1a1a1a" } + ] + } + } +} diff --git a/packages/github_tools/styles/tokens.json b/packages/github_tools/styles/tokens.json new file mode 100644 index 000000000..b1b829c7b --- /dev/null +++ b/packages/github_tools/styles/tokens.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-styles.schema.json", + "schemaVersion": "2.0.0", + "colors": { + "statusSuccess": "#28a745", + "statusFailure": "#dc3545", + "statusPending": "#ffc107", + "statusInProgress": "#17a2b8", + "statusCancelled": "#6c757d", + "statusSkipped": "#868e96", + "logBackground": "#1e1e1e", + "logText": "#d4d4d4", + "logError": "#f48771", + "logWarning": "#cca700", + "logInfo": "#3794ff", + "cardBorder": "#dee2e6" + }, + "spacing": { + "viewerPadding": "16px", + "runListGap": "8px", + "filterGap": "16px", + "analysisGrid": "24px", + "logPadding": "12px" + }, + "shadows": { + "card": "0 2px 8px rgba(0, 0, 0, 0.1)", + "runItem": "0 1px 4px rgba(0, 0, 0, 0.08)", + "logViewer": "inset 0 2px 4px rgba(0, 0, 0, 0.2)" + }, + "typography": { + "logFont": "JetBrains Mono, Consolas, Monaco, monospace", + "logFontSize": "0.875rem", + "logLineHeight": "1.5" + }, + "borderRadius": { + "card": "8px", + "badge": "16px", + "logViewer": "4px" + } +} diff --git a/packages/irc_webchat/components/ui.json b/packages/irc_webchat/components/ui.json new file mode 100644 index 000000000..7331cb78c --- /dev/null +++ b/packages/irc_webchat/components/ui.json @@ -0,0 +1,388 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script-components.schema.json", + "schemaVersion": "2.0.0", + "package": "irc_webchat", + "description": "IRC Webchat components for real-time messaging", + "components": [ + { + "id": "irc_webchat", + "name": "IRCWebchat", + "description": "Main IRC webchat container with channels, messages, and users", + "props": [ + { + "name": "channelName", + "type": "string", + "required": true, + "description": "Initial channel to join" + }, + { + "name": "userId", + "type": "string", + "required": false, + "description": "Current user ID" + }, + { + "name": "username", + "type": "string", + "required": false, + "description": "Current username" + } + ], + "render": { + "type": "element", + "template": { + "type": "Box", + "className": "irc-webchat", + "sx": { + "display": "flex", + "height": "100%", + "minHeight": "500px", + "border": "1px solid", + "borderColor": "divider", + "borderRadius": 1 + }, + "children": [ + { + "type": "ChannelList", + "channels": "{{channels}}", + "activeChannel": "{{channelName}}", + "onChannelSelect": "{{onChannelSelect}}" + }, + { + "type": "Box", + "sx": { + "flex": 1, + "display": "flex", + "flexDirection": "column" + }, + "children": [ + { + "type": "Box", + "className": "irc-header", + "sx": { + "p": 2, + "borderBottom": "1px solid", + "borderColor": "divider", + "bgcolor": "background.paper" + }, + "children": [ + { + "type": "Text", + "variant": "h6", + "children": "#{{channelName}}" + } + ] + }, + { + "type": "MessageList", + "messages": "{{messages}}", + "sx": { "flex": 1 } + }, + { + "type": "MessageInput", + "onSend": "{{onSendMessage}}", + "onCommand": "{{onCommand}}" + } + ] + }, + { + "type": "UserList", + "users": "{{onlineUsers}}", + "channelName": "{{channelName}}" + } + ] + } + } + }, + { + "id": "channel_list", + "name": "ChannelList", + "description": "Sidebar list of available IRC channels", + "props": [ + { + "name": "channels", + "type": "array", + "required": true, + "description": "Array of channel objects" + }, + { + "name": "activeChannel", + "type": "string", + "required": false, + "description": "Currently active channel name" + }, + { + "name": "onChannelSelect", + "type": "function", + "required": false, + "description": "Callback when channel is selected" + } + ], + "render": { + "type": "element", + "template": { + "type": "Box", + "className": "irc-channel-list", + "sx": { + "width": 200, + "borderRight": "1px solid", + "borderColor": "divider", + "bgcolor": "background.default" + }, + "children": [ + { + "type": "Box", + "sx": { "p": 2, "borderBottom": "1px solid", "borderColor": "divider" }, + "children": [ + { + "type": "Text", + "variant": "subtitle2", + "color": "text.secondary", + "children": "CHANNELS" + } + ] + }, + { + "type": "List", + "dense": true, + "children": { + "type": "map", + "items": "{{channels}}", + "template": { + "type": "ListItem", + "button": true, + "selected": "{{item.name === activeChannel}}", + "onClick": "{{() => onChannelSelect(item.name)}}", + "children": [ + { + "type": "ListItemText", + "primary": "#{{item.name}}" + } + ] + } + } + } + ] + } + } + }, + { + "id": "message_list", + "name": "MessageList", + "description": "Scrollable list of chat messages", + "props": [ + { + "name": "messages", + "type": "array", + "required": true, + "description": "Array of message objects" + } + ], + "render": { + "type": "element", + "template": { + "type": "Box", + "className": "irc-message-list", + "sx": { + "flex": 1, + "overflow": "auto", + "p": 2, + "bgcolor": "background.paper" + }, + "children": { + "type": "map", + "items": "{{messages}}", + "template": { + "type": "Box", + "className": "irc-message irc-message--{{item.type}}", + "sx": { "mb": 1 }, + "children": [ + { + "type": "Flex", + "gap": 1, + "alignItems": "baseline", + "children": [ + { + "type": "Text", + "variant": "caption", + "color": "text.secondary", + "children": "{{formatTime(item.timestamp)}}" + }, + { + "type": "conditional", + "condition": "{{item.type === 'message'}}", + "then": { + "type": "Text", + "variant": "body2", + "children": [ + { + "type": "Text", + "component": "span", + "fontWeight": "bold", + "color": "primary.main", + "children": "<{{item.username}}> " + }, + "{{item.message}}" + ] + }, + "else": { + "type": "Text", + "variant": "body2", + "fontStyle": "italic", + "color": "text.secondary", + "children": "* {{item.message}}" + } + } + ] + } + ] + } + } + } + } + }, + { + "id": "user_list", + "name": "UserList", + "description": "Sidebar list of online users in channel", + "props": [ + { + "name": "users", + "type": "array", + "required": true, + "description": "Array of online user objects" + }, + { + "name": "channelName", + "type": "string", + "required": false, + "description": "Current channel name" + } + ], + "render": { + "type": "element", + "template": { + "type": "Box", + "className": "irc-user-list", + "sx": { + "width": 160, + "borderLeft": "1px solid", + "borderColor": "divider", + "bgcolor": "background.default" + }, + "children": [ + { + "type": "Box", + "sx": { "p": 2, "borderBottom": "1px solid", "borderColor": "divider" }, + "children": [ + { + "type": "Text", + "variant": "subtitle2", + "color": "text.secondary", + "children": "USERS ({{users.length}})" + } + ] + }, + { + "type": "List", + "dense": true, + "children": { + "type": "map", + "items": "{{users}}", + "template": { + "type": "ListItem", + "children": [ + { + "type": "ListItemIcon", + "sx": { "minWidth": 24 }, + "children": [ + { + "type": "Box", + "component": "span", + "sx": { + "width": 8, + "height": 8, + "borderRadius": "50%", + "bgcolor": "success.main", + "display": "inline-block" + } + } + ] + }, + { + "type": "ListItemText", + "primary": "{{item.username}}" + } + ] + } + } + } + ] + } + } + }, + { + "id": "message_input", + "name": "MessageInput", + "description": "Input field for sending messages and commands", + "props": [ + { + "name": "onSend", + "type": "function", + "required": true, + "description": "Callback when message is sent" + }, + { + "name": "onCommand", + "type": "function", + "required": false, + "description": "Callback when command is entered" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "Type a message or /help for commands..." + } + ], + "render": { + "type": "element", + "template": { + "type": "Box", + "className": "irc-message-input", + "sx": { + "p": 2, + "borderTop": "1px solid", + "borderColor": "divider", + "bgcolor": "background.paper" + }, + "children": [ + { + "type": "Flex", + "gap": 1, + "children": [ + { + "type": "TextField", + "fullWidth": true, + "size": "small", + "variant": "outlined", + "placeholder": "{{placeholder}}", + "value": "{{inputValue}}", + "onChange": "{{handleInputChange}}", + "onKeyPress": "{{handleKeyPress}}" + }, + { + "type": "Button", + "variant": "contained", + "color": "primary", + "onClick": "{{handleSend}}", + "children": "Send" + } + ] + } + ] + } + } + } + ] +} diff --git a/packages/irc_webchat/package.json b/packages/irc_webchat/package.json new file mode 100644 index 000000000..aad103fff --- /dev/null +++ b/packages/irc_webchat/package.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-metadata.schema.json", + "packageId": "irc_webchat", + "name": "IRC Webchat", + "version": "1.0.0", + "description": "Classic IRC-style webchat with channels, commands, online users, and real-time messaging. Perfect for community chat rooms.", + "author": "MetaBuilder Team", + "license": "MIT", + "category": "social", + "icon": "๐Ÿ’ฌ", + "minLevel": 2, + "primary": true, + "tags": [ + "chat", + "irc", + "messaging", + "realtime" + ], + "dependencies": {}, + "devDependencies": { + "lua_test": "*" + }, + "exports": { + "components": [ + "IRCWebchat", + "ChannelList", + "MessageList", + "UserList", + "MessageInput" + ], + "scripts": [ + "send_message", + "handle_command", + "format_time", + "user_join", + "user_leave" + ] + }, + "tests": { + "scripts": [ + "tests/metadata.test.lua", + "tests/components.test.lua" + ], + "parameterized": [ + { + "parameters": "tests/metadata.cases.json" + }, + { + "parameters": "tests/components.cases.json" + } + ] + }, + "schema": { + "entities": [ + "IRCChannel", + "IRCMessage", + "IRCMembership" + ], + "path": "schema/entities.yaml" + } +} diff --git a/packages/irc_webchat/permissions/roles.json b/packages/irc_webchat/permissions/roles.json new file mode 100644 index 000000000..86a59eb63 --- /dev/null +++ b/packages/irc_webchat/permissions/roles.json @@ -0,0 +1,85 @@ +{ + "$schema": "https://metabuilder.dev/schemas/permissions.schema.json", + "schemaVersion": "1.0.0", + "package": "irc_webchat", + "description": "IRC Webchat access permissions", + "permissions": [ + { + "id": "irc.channel.view", + "name": "View IRC Channels", + "description": "View IRC channels", + "resource": "irc_channel", + "action": "read", + "scope": "global", + "minLevel": 2 + }, + { + "id": "irc.channel.join", + "name": "Join IRC Channels", + "description": "Join IRC channels", + "resource": "irc_channel", + "action": "join", + "scope": "global", + "minLevel": 2 + }, + { + "id": "irc.message.send", + "name": "Send IRC Messages", + "description": "Send IRC messages", + "resource": "irc_message", + "action": "create", + "scope": "channel", + "minLevel": 2 + }, + { + "id": "irc.channel.create", + "name": "Create IRC Channels", + "description": "Create IRC channels", + "resource": "irc_channel", + "action": "create", + "scope": "global", + "minLevel": 3 + }, + { + "id": "irc.channel.moderate", + "name": "Moderate IRC Channels", + "description": "Moderate IRC channels (kick, ban, mute users)", + "resource": "irc_channel", + "action": "moderate", + "scope": "channel", + "minLevel": 3 + }, + { + "id": "irc.channel.delete", + "name": "Delete IRC Channels", + "description": "Delete IRC channels", + "resource": "irc_channel", + "action": "delete", + "scope": "global", + "minLevel": 4 + } + ], + "resources": [ + { + "id": "irc_channel", + "name": "IRC Channel", + "type": "entity", + "description": "IRC chat channel", + "actions": ["read", "join", "create", "moderate", "delete"] + }, + { + "id": "irc_message", + "name": "IRC Message", + "type": "entity", + "description": "IRC chat message", + "actions": ["read", "create", "delete"] + }, + { + "id": "irc_membership", + "name": "IRC Membership", + "type": "entity", + "description": "IRC channel membership", + "actions": ["read", "create", "delete"] + } + ] +} diff --git a/packages/irc_webchat/scripts/functions.json b/packages/irc_webchat/scripts/functions.json new file mode 100644 index 000000000..445d5c164 --- /dev/null +++ b/packages/irc_webchat/scripts/functions.json @@ -0,0 +1,170 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script.schema.json", + "schemaVersion": "2.2.0", + "package": "irc_webchat", + "description": "IRC Webchat message handling and command processing functions", + "functions": [ + { + "id": "irc_send_message", + "name": "sendMessage", + "exported": true, + "description": "Send a chat message to a channel", + "category": "commands", + "luaScript": "send_message.lua", + "parameters": [ + { + "name": "channelId", + "type": "string", + "description": "Channel identifier" + }, + { + "name": "username", + "type": "string", + "description": "Username of the sender" + }, + { + "name": "userId", + "type": "string", + "description": "User identifier" + }, + { + "name": "message", + "type": "string", + "description": "Message content to send" + } + ], + "returns": { + "type": "ChatMessage", + "description": "Chat message object" + } + }, + { + "id": "irc_handle_command", + "name": "handleCommand", + "exported": true, + "description": "Process IRC commands like /help, /users, /clear, /me", + "category": "commands", + "luaScript": "handle_command.lua", + "parameters": [ + { + "name": "command", + "type": "string", + "description": "IRC command string (e.g., /help, /users, /clear, /me )" + }, + { + "name": "channelId", + "type": "string", + "description": "Channel identifier" + }, + { + "name": "username", + "type": "string", + "description": "Current username" + }, + { + "name": "onlineUsers", + "type": "array", + "description": "List of online usernames" + } + ], + "returns": { + "type": "IRCMessage", + "description": "Response message object" + } + }, + { + "id": "irc_format_time", + "name": "formatTime", + "exported": true, + "description": "Format timestamps for display in HH:MM AM/PM format", + "category": "formatting", + "luaScript": "format_time.lua", + "parameters": [ + { + "name": "timestamp", + "type": "number", + "description": "Unix timestamp in milliseconds" + } + ], + "returns": { + "type": "string", + "description": "Formatted time string in HH:MM AM/PM format" + } + }, + { + "id": "irc_user_join", + "name": "userJoin", + "exported": true, + "description": "Handle user joining a channel", + "category": "events", + "luaScript": "user_join.lua", + "parameters": [ + { + "name": "channelId", + "type": "string", + "description": "Channel identifier" + }, + { + "name": "username", + "type": "string", + "description": "Username of the user joining" + }, + { + "name": "userId", + "type": "string", + "description": "User identifier of the user joining" + } + ], + "returns": { + "type": "JoinMessage", + "description": "Join notification message object" + } + }, + { + "id": "irc_user_leave", + "name": "userLeave", + "exported": true, + "description": "Handle user leaving a channel", + "category": "events", + "luaScript": "user_leave.lua", + "parameters": [ + { + "name": "channelId", + "type": "string", + "description": "Channel identifier" + }, + { + "name": "username", + "type": "string", + "description": "Username of the user leaving" + }, + { + "name": "userId", + "type": "string", + "description": "User identifier of the user leaving" + } + ], + "returns": { + "type": "LeaveMessage", + "description": "Leave notification message object" + } + }, + { + "id": "irc_init", + "name": "init", + "exported": false, + "description": "Lifecycle hooks for installation and removal", + "category": "lifecycle", + "luaScript": "init.lua" + } + ], + "exports": { + "functions": [ + "sendMessage", + "handleCommand", + "formatTime", + "userJoin", + "userLeave" + ] + } +} diff --git a/packages/irc_webchat/storybook/stories.json b/packages/irc_webchat/storybook/stories.json new file mode 100644 index 000000000..607364079 --- /dev/null +++ b/packages/irc_webchat/storybook/stories.json @@ -0,0 +1,193 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-storybook.schema.json", + "featured": true, + "title": "IRC Webchat Components", + "description": "Classic IRC-style webchat with channels, commands, and real-time messaging", + "stories": [ + { + "name": "IRCWebchat", + "render": "webchat", + "description": "Complete IRC webchat interface with channels, messages, and users", + "args": { + "channelName": "general", + "channels": [ + { "name": "general", "topic": "General discussion" }, + { "name": "help", "topic": "Help and support" }, + { "name": "random", "topic": "Off-topic chat" } + ], + "messages": [ + { + "id": "msg_1", + "username": "System", + "userId": "system", + "message": "Welcome to #general!", + "type": "system", + "timestamp": 1735776000000 + }, + { + "id": "msg_2", + "username": "alice", + "userId": "user_alice", + "message": "Hey everyone!", + "type": "message", + "timestamp": 1735776060000 + }, + { + "id": "msg_3", + "username": "bob", + "userId": "user_bob", + "message": "Hi alice, how's it going?", + "type": "message", + "timestamp": 1735776120000 + } + ], + "onlineUsers": [ + { "username": "alice", "status": "online" }, + { "username": "bob", "status": "online" }, + { "username": "charlie", "status": "away" } + ] + } + }, + { + "name": "ChannelList", + "render": "channel_list", + "description": "Sidebar with list of available channels", + "args": { + "channels": [ + { "name": "general", "topic": "General discussion" }, + { "name": "dev", "topic": "Development talk" }, + { "name": "help", "topic": "Help and support" } + ], + "activeChannel": "general" + } + }, + { + "name": "MessageList", + "render": "message_list", + "description": "Scrollable list of chat messages", + "args": { + "messages": [ + { + "id": "msg_1", + "username": "alice", + "message": "Hello world!", + "type": "message", + "timestamp": 1735776000000 + }, + { + "id": "msg_2", + "username": "System", + "message": "bob has joined the channel", + "type": "join", + "timestamp": 1735776060000 + }, + { + "id": "msg_3", + "username": "bob", + "message": "waves hello", + "type": "system", + "timestamp": 1735776120000 + } + ] + } + }, + { + "name": "UserList", + "render": "user_list", + "description": "Sidebar with online users", + "args": { + "channelName": "general", + "users": [ + { "username": "alice", "status": "online" }, + { "username": "bob", "status": "online" }, + { "username": "charlie", "status": "away" }, + { "username": "david", "status": "online" } + ] + } + }, + { + "name": "MessageInput", + "render": "message_input", + "description": "Input field for sending messages", + "args": { + "placeholder": "Type a message or /help for commands..." + } + } + ], + "renders": { + "webchat": { + "description": "Complete IRC webchat interface", + "featured": true + }, + "channel_list": { + "description": "Channel navigation sidebar" + }, + "message_list": { + "description": "Chat message display" + }, + "user_list": { + "description": "Online users sidebar" + }, + "message_input": { + "description": "Message input with command support" + } + }, + "defaultContext": { + "user": { + "id": "demo-user", + "username": "demo_user", + "level": 2, + "email": "demo@example.com" + }, + "tenant": { + "id": "demo-tenant", + "name": "Demo Organization" + } + }, + "contextVariants": [ + { + "name": "Standard User", + "description": "Can view channels and send messages", + "context": { + "user": { + "username": "user", + "level": 2 + } + } + }, + { + "name": "Moderator", + "description": "Can moderate channels", + "context": { + "user": { + "username": "moderator", + "level": 3 + } + } + }, + { + "name": "Admin", + "description": "Full IRC management access", + "context": { + "user": { + "username": "admin", + "level": 4 + } + } + } + ], + "scripts": { + "renderFunctions": ["webchat", "channel_list", "message_list", "user_list", "message_input"], + "ignoredScripts": ["tests", "init"] + }, + "parameters": { + "layout": "fullscreen", + "backgrounds": { + "default": "light", + "values": [ + { "name": "light", "value": "#ffffff" }, + { "name": "dark", "value": "#1a1a1a" } + ] + } + } +} diff --git a/packages/irc_webchat/styles/tokens.json b/packages/irc_webchat/styles/tokens.json new file mode 100644 index 000000000..1b8ebf01f --- /dev/null +++ b/packages/irc_webchat/styles/tokens.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-styles.schema.json", + "schemaVersion": "2.0.0", + "colors": { + "channelActive": "#1976d2", + "channelInactive": "#666666", + "userOnline": "#4caf50", + "userAway": "#ff9800", + "userOffline": "#9e9e9e", + "messageSystem": "#757575", + "messageJoin": "#4caf50", + "messageLeave": "#f44336", + "messageAction": "#9c27b0", + "messageMention": "#ff5722", + "inputBorder": "#dee2e6", + "headerBg": "#f5f5f5", + "sidebarBg": "#fafafa" + }, + "spacing": { + "chatPadding": "16px", + "messagePadding": "8px", + "channelListWidth": "200px", + "userListWidth": "160px", + "inputHeight": "48px", + "headerHeight": "56px", + "messageGap": "4px" + }, + "shadows": { + "chatContainer": "0 2px 8px rgba(0, 0, 0, 0.12)", + "header": "0 1px 3px rgba(0, 0, 0, 0.08)", + "input": "inset 0 1px 2px rgba(0, 0, 0, 0.05)" + }, + "typography": { + "messageFont": "IBM Plex Mono, monospace", + "timestampSize": "11px", + "usernameWeight": "600", + "channelNameSize": "14px" + }, + "borders": { + "sidebarDivider": "1px solid #e0e0e0", + "messageDivider": "1px solid #f0f0f0", + "inputBorder": "1px solid #dee2e6" + } +} diff --git a/packages/json_script_example/components/ui.json b/packages/json_script_example/components/ui.json new file mode 100644 index 000000000..12b1d0710 --- /dev/null +++ b/packages/json_script_example/components/ui.json @@ -0,0 +1,424 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script-components.schema.json", + "schemaVersion": "2.0.0", + "package": "json_script_example", + "description": "UI component examples demonstrating JSON script patterns", + "components": [ + { + "id": "expression_demo", + "name": "ExpressionDemo", + "description": "Interactive expression calculator component that renders a form with two number inputs and displays results of all expression operations", + "props": [ + { + "name": "initialA", + "type": "number", + "required": false, + "default": 10, + "description": "Initial value for first number" + }, + { + "name": "initialB", + "type": "number", + "required": false, + "default": 5, + "description": "Initial value for second number" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "expression-demo", + "children": [ + { + "type": "Text", + "variant": "h5", + "fontWeight": "bold", + "children": "Expression Calculator" + }, + { + "type": "Stack", + "direction": "row", + "gap": 2, + "mt": 2, + "children": [ + { + "type": "TextField", + "label": "First Number", + "inputType": "number", + "value": "{{state.a}}", + "onChange": "{{handlers.setA}}" + }, + { + "type": "TextField", + "label": "Second Number", + "inputType": "number", + "value": "{{state.b}}", + "onChange": "{{handlers.setB}}" + } + ] + }, + { + "type": "Box", + "mt": 2, + "children": [ + { + "type": "component", + "name": "ResultDisplay", + "props": { + "result": "{{computed.result}}" + } + } + ] + } + ] + } + }, + "state": { + "a": "{{props.initialA}}", + "b": "{{props.initialB}}" + }, + "handlers": { + "setA": { + "params": ["value"], + "body": [ + { + "type": "setState", + "updates": { + "a": "{{params.value}}" + } + } + ] + }, + "setB": { + "params": ["value"], + "body": [ + { + "type": "setState", + "updates": { + "b": "{{params.value}}" + } + } + ] + } + }, + "computed": { + "result": { + "body": [ + { + "type": "return", + "value": { + "type": "call_expression", + "callee": "{{imports.script.all_expressions}}", + "args": ["{{state.a}}", "{{state.b}}"] + } + } + ] + } + } + }, + { + "id": "operator_demo", + "name": "OperatorDemo", + "description": "Interactive operator demonstration component showing all operator results in a categorized table format", + "props": [ + { + "name": "x", + "type": "number", + "required": false, + "default": 10, + "description": "First operand" + }, + { + "name": "y", + "type": "number", + "required": false, + "default": 5, + "description": "Second operand" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "operator-demo", + "children": [ + { + "type": "Text", + "variant": "h5", + "fontWeight": "bold", + "children": "Operator Demonstration" + }, + { + "type": "Text", + "variant": "body1", + "color": "secondary", + "mt": 1, + "children": "x = {{props.x}}, y = {{props.y}}" + }, + { + "type": "Grid", + "container": true, + "spacing": 3, + "mt": 2, + "children": [ + { + "type": "Grid", + "item": true, + "xs": 12, + "md": 6, + "children": [ + { + "type": "Text", + "variant": "h6", + "children": "Arithmetic" + }, + { + "type": "List", + "dense": true, + "children": [ + { + "type": "ListItem", + "children": "x + y = {{computed.operators.arithmetic.add}}" + }, + { + "type": "ListItem", + "children": "x - y = {{computed.operators.arithmetic.subtract}}" + }, + { + "type": "ListItem", + "children": "x * y = {{computed.operators.arithmetic.multiply}}" + }, + { + "type": "ListItem", + "children": "x / y = {{computed.operators.arithmetic.divide}}" + }, + { + "type": "ListItem", + "children": "x % y = {{computed.operators.arithmetic.modulo}}" + } + ] + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 12, + "md": 6, + "children": [ + { + "type": "Text", + "variant": "h6", + "children": "Comparison" + }, + { + "type": "List", + "dense": true, + "children": [ + { + "type": "ListItem", + "children": "x == y: {{computed.operators.comparison.equal}}" + }, + { + "type": "ListItem", + "children": "x != y: {{computed.operators.comparison.notEqual}}" + }, + { + "type": "ListItem", + "children": "x > y: {{computed.operators.comparison.greaterThan}}" + }, + { + "type": "ListItem", + "children": "x < y: {{computed.operators.comparison.lessThan}}" + } + ] + } + ] + } + ] + } + ] + } + }, + "computed": { + "operators": { + "body": [ + { + "type": "return", + "value": { + "type": "call_expression", + "callee": "{{imports.script.all_operators}}", + "args": ["{{props.x}}", "{{props.y}}"] + } + } + ] + } + } + }, + { + "id": "result_display", + "name": "ResultDisplay", + "description": "Displays expression results in a formatted card layout", + "props": [ + { + "name": "result", + "type": "object", + "required": true, + "description": "Result object from all_expressions function" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "result-display", + "sx": { + "p": 2 + }, + "children": [ + { + "type": "Text", + "variant": "h6", + "fontWeight": "bold", + "children": "Results" + }, + { + "type": "Grid", + "container": true, + "spacing": 2, + "mt": 1, + "children": [ + { + "type": "Grid", + "item": true, + "xs": 6, + "children": [ + { + "type": "Text", + "variant": "caption", + "color": "secondary", + "children": "Sum" + }, + { + "type": "Text", + "variant": "body1", + "fontWeight": "medium", + "children": "{{props.result.sum}}" + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 6, + "children": [ + { + "type": "Text", + "variant": "caption", + "color": "secondary", + "children": "Difference" + }, + { + "type": "Text", + "variant": "body1", + "fontWeight": "medium", + "children": "{{props.result.diff}}" + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 6, + "children": [ + { + "type": "Text", + "variant": "caption", + "color": "secondary", + "children": "Product" + }, + { + "type": "Text", + "variant": "body1", + "fontWeight": "medium", + "children": "{{props.result.product}}" + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 6, + "children": [ + { + "type": "Text", + "variant": "caption", + "color": "secondary", + "children": "Maximum" + }, + { + "type": "Text", + "variant": "body1", + "fontWeight": "medium", + "children": "{{props.result.max}}" + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 12, + "children": [ + { + "type": "Text", + "variant": "caption", + "color": "secondary", + "children": "Both Positive?" + }, + { + "type": "Chip", + "label": "{{props.result.bothPositive ? 'Yes' : 'No'}}", + "color": "{{props.result.bothPositive ? 'success' : 'error'}}", + "size": "small" + } + ] + }, + { + "type": "Grid", + "item": true, + "xs": 12, + "children": [ + { + "type": "Text", + "variant": "caption", + "color": "secondary", + "children": "Message" + }, + { + "type": "Text", + "variant": "body2", + "sx": { + "fontFamily": "monospace" + }, + "children": "{{props.result.message}}" + } + ] + } + ] + } + ] + } + } + } + ], + "imports": [ + { + "from": "script", + "import": ["all_expressions", "all_operators"] + } + ] +} diff --git a/packages/json_script_example/package.json b/packages/json_script_example/package.json new file mode 100644 index 000000000..99e28c616 --- /dev/null +++ b/packages/json_script_example/package.json @@ -0,0 +1,50 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-metadata.schema.json", + "packageId": "json_script_example", + "name": "JSON Script Example", + "version": "1.0.0", + "description": "Comprehensive example demonstrating the full JSON script specification", + "author": "MetaBuilder", + "license": "MIT", + "category": "examples", + "minLevel": 0, + "primary": false, + "dependencies": {}, + "devDependencies": { + "lua_test": "*" + }, + "exports": { + "components": [ + "ExpressionDemo", + "OperatorDemo", + "ResultDisplay" + ], + "scripts": [ + "all_expressions", + "all_statements", + "all_operators", + "control_flow", + "data_structures" + ], + "types": [ + "ArithmeticResult", + "ComparisonResult", + "LogicalResult", + "OperatorsDemoResult", + "ExpressionsDemoResult", + "StatementsDemoResult", + "DataStructuresResult", + "Classification", + "TestResult", + "ValidationResult" + ] + }, + "tests": { + "parameterized": [ + { + "logic": "tests/math.test.logic.json", + "parameters": "tests/math.test.parameters.json" + } + ] + } +} diff --git a/packages/json_script_example/permissions/roles.json b/packages/json_script_example/permissions/roles.json new file mode 100644 index 000000000..949431b08 --- /dev/null +++ b/packages/json_script_example/permissions/roles.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://metabuilder.dev/schemas/permissions.schema.json", + "schemaVersion": "1.0.0", + "package": "json_script_example", + "description": "Permission definitions for JSON Script Example package", + "permissions": [ + { + "id": "example.view", + "name": "View Examples", + "description": "View JSON script examples and demos", + "resource": "json_script_example", + "action": "read", + "scope": "global", + "minLevel": 0 + }, + { + "id": "example.execute", + "name": "Execute Examples", + "description": "Execute JSON script example functions", + "resource": "json_script_example", + "action": "execute", + "scope": "global", + "minLevel": 1 + }, + { + "id": "example.modify", + "name": "Modify Examples", + "description": "Modify and experiment with JSON script examples", + "resource": "json_script_example", + "action": "write", + "scope": "global", + "minLevel": 2 + } + ], + "resources": [ + { + "id": "json_script_example", + "name": "JSON Script Example", + "type": "package", + "description": "JSON script example and demonstration resources", + "actions": ["read", "execute", "write"] + } + ] +} diff --git a/packages/json_script_example/scripts/functions.json b/packages/json_script_example/scripts/functions.json new file mode 100644 index 000000000..7c4fc657b --- /dev/null +++ b/packages/json_script_example/scripts/functions.json @@ -0,0 +1,136 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script.schema.json", + "schemaVersion": "2.2.0", + "package": "json_script_example", + "description": "Complete demonstration of JSON script specification with expressions, statements, operators, and control flow", + "constants": [ + { + "id": "max_value", + "name": "MAX_VALUE", + "value": 100, + "type": "number", + "exported": true, + "description": "Maximum allowed value for calculations" + }, + { + "id": "app_name", + "name": "APP_NAME", + "value": "JSON Script Demo", + "type": "string", + "exported": true, + "description": "Application display name" + }, + { + "id": "config", + "name": "DEFAULT_CONFIG", + "type": "object", + "value": { + "debug": true, + "timeout": 5000, + "maxRetries": 3 + }, + "exported": true, + "description": "Default application configuration" + } + ], + "functions": [ + { + "id": "all_expressions_demo", + "name": "all_expressions", + "exported": true, + "description": "Demonstrates all JSON script expression types including binary, logical, unary, conditional, and template literals", + "category": "demo", + "params": [ + { + "name": "a", + "type": "number", + "description": "First number for arithmetic and comparison operations" + }, + { + "name": "b", + "type": "number", + "description": "Second number for arithmetic and comparison operations" + } + ], + "returnType": "ExpressionsDemoResult", + "luaScript": "expressions.lua" + }, + { + "id": "all_statements_demo", + "name": "all_statements", + "exported": true, + "description": "Demonstrates all statement types including declarations, loops, conditionals, and error handling", + "category": "demo", + "params": [ + { + "name": "items", + "type": "array", + "description": "Array of numbers to process and calculate statistics on" + } + ], + "returnType": "StatementsDemoResult", + "luaScript": "statements.lua" + }, + { + "id": "all_operators_demo", + "name": "all_operators", + "exported": true, + "description": "Demonstrates all supported operators: arithmetic, comparison, logical, and unary", + "category": "demo", + "params": [ + { + "name": "x", + "type": "number", + "description": "First operand" + }, + { + "name": "y", + "type": "number", + "description": "Second operand" + } + ], + "returnType": "OperatorsDemoResult", + "luaScript": "operators.lua" + }, + { + "id": "control_flow_demo", + "name": "control_flow", + "exported": true, + "description": "Demonstrates control flow patterns with nested if/else for classification", + "category": "demo", + "params": [ + { + "name": "value", + "type": "number", + "description": "Number to classify" + } + ], + "returnType": "Classification", + "luaScript": "control_flow.lua" + }, + { + "id": "data_structures_demo", + "name": "data_structures", + "exported": true, + "description": "Demonstrates working with objects and arrays including nested structures and member access", + "category": "demo", + "params": [], + "returnType": "DataStructuresResult", + "luaScript": "data_structures.lua" + } + ], + "exports": { + "functions": [ + "all_expressions", + "all_statements", + "all_operators", + "control_flow", + "data_structures" + ], + "constants": [ + "MAX_VALUE", + "APP_NAME", + "DEFAULT_CONFIG" + ] + } +} diff --git a/packages/json_script_example/storybook/stories.json b/packages/json_script_example/storybook/stories.json new file mode 100644 index 000000000..3def0945e --- /dev/null +++ b/packages/json_script_example/storybook/stories.json @@ -0,0 +1,251 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-storybook.schema.json", + "featured": false, + "title": "JSON Script Examples", + "description": "Comprehensive examples demonstrating the full JSON script specification", + "stories": [ + { + "name": "All Expressions", + "render": "all_expressions", + "description": "Demonstrates all expression types: binary, logical, unary, conditional, template literals", + "type": "function", + "args": { + "a": 10, + "b": 5 + }, + "argControls": { + "a": { + "type": "number", + "default": 10, + "min": -100, + "max": 100, + "step": 1, + "description": "First number" + }, + "b": { + "type": "number", + "default": 5, + "min": -100, + "max": 100, + "step": 1, + "description": "Second number" + } + } + }, + { + "name": "All Statements", + "render": "all_statements", + "description": "Demonstrates all statement types: declarations, loops, conditionals, error handling", + "type": "function", + "args": { + "items": [1, 2, 3, 4, 5] + }, + "argControls": { + "items": { + "type": "json", + "default": [1, 2, 3, 4, 5], + "description": "Array of numbers to process" + } + } + }, + { + "name": "All Operators", + "render": "all_operators", + "description": "Demonstrates all operators: arithmetic, comparison, logical, unary", + "type": "function", + "args": { + "x": 10, + "y": 5 + }, + "argControls": { + "x": { + "type": "number", + "default": 10, + "min": -100, + "max": 100, + "step": 1, + "description": "First operand" + }, + "y": { + "type": "number", + "default": 5, + "min": -100, + "max": 100, + "step": 1, + "description": "Second operand" + } + } + }, + { + "name": "Control Flow", + "render": "control_flow", + "description": "Demonstrates control flow patterns with nested if/else classification", + "type": "function", + "args": { + "value": 42 + }, + "argControls": { + "value": { + "type": "number", + "default": 42, + "min": -100, + "max": 200, + "step": 1, + "description": "Number to classify" + } + } + }, + { + "name": "Data Structures", + "render": "data_structures", + "description": "Demonstrates working with objects and arrays", + "type": "function", + "args": {} + }, + { + "name": "Expression Demo Component", + "render": "ExpressionDemo", + "description": "Interactive expression calculator component", + "type": "component", + "args": { + "initialA": 10, + "initialB": 5 + }, + "argControls": { + "initialA": { + "type": "number", + "default": 10, + "min": -100, + "max": 100, + "step": 1, + "description": "Initial value for first number" + }, + "initialB": { + "type": "number", + "default": 5, + "min": -100, + "max": 100, + "step": 1, + "description": "Initial value for second number" + } + } + }, + { + "name": "Operator Demo Component", + "render": "OperatorDemo", + "description": "Interactive operator demonstration showing all operator results", + "type": "component", + "args": { + "x": 10, + "y": 5 + }, + "argControls": { + "x": { + "type": "number", + "default": 10, + "min": -100, + "max": 100, + "step": 1, + "description": "First operand" + }, + "y": { + "type": "number", + "default": 5, + "min": -100, + "max": 100, + "step": 1, + "description": "Second operand" + } + } + } + ], + "renders": { + "all_expressions": { + "description": "All expression types demo", + "featured": true + }, + "all_statements": { + "description": "All statement types demo" + }, + "all_operators": { + "description": "All operators demo", + "featured": true + }, + "control_flow": { + "description": "Control flow patterns demo" + }, + "data_structures": { + "description": "Data structures demo" + }, + "ExpressionDemo": { + "description": "Interactive expression calculator" + }, + "OperatorDemo": { + "description": "Interactive operator demonstration" + } + }, + "defaultContext": { + "user": { + "id": "demo-user", + "username": "demo_user", + "level": 1, + "email": "demo@example.com" + }, + "tenant": { + "id": "demo-tenant", + "name": "Demo Organization" + } + }, + "contextVariants": [ + { + "name": "Public User", + "description": "Can view examples", + "context": { + "user": { + "username": "public_user", + "level": 0 + } + } + }, + { + "name": "Standard User", + "description": "Can view and execute examples", + "context": { + "user": { + "username": "user", + "level": 1 + } + } + }, + { + "name": "Moderator", + "description": "Can modify examples", + "context": { + "user": { + "username": "moderator", + "level": 2 + } + } + } + ], + "scripts": { + "renderFunctions": [ + "all_expressions", + "all_statements", + "all_operators", + "control_flow", + "data_structures" + ], + "ignoredScripts": ["tests"] + }, + "parameters": { + "layout": "padded", + "backgrounds": { + "default": "light", + "values": [ + { "name": "light", "value": "#fafafa" }, + { "name": "dark", "value": "#212121" } + ] + } + } +} diff --git a/packages/json_script_example/styles/tokens.json b/packages/json_script_example/styles/tokens.json new file mode 100644 index 000000000..2b150e29d --- /dev/null +++ b/packages/json_script_example/styles/tokens.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-styles.schema.json", + "schemaVersion": "2.0.0", + "colors": { + "primary": "#2196F3", + "secondary": "#FFC107", + "success": "#4CAF50", + "error": "#F44336", + "warning": "#FF9800", + "info": "#00BCD4", + "background": "#FAFAFA", + "text": "#212121", + "expressionHighlight": "#E3F2FD", + "operatorHighlight": "#FFF3E0", + "resultPositive": "#C8E6C9", + "resultNegative": "#FFCDD2" + }, + "spacing": { + "xs": "4px", + "sm": "8px", + "md": "16px", + "lg": "24px", + "xl": "32px", + "demoCard": "20px", + "resultGrid": "12px" + }, + "shadows": { + "demoCard": "0 2px 8px rgba(33, 150, 243, 0.15)", + "resultCard": "0 1px 4px rgba(0, 0, 0, 0.08)", + "operatorTable": "0 1px 3px rgba(0, 0, 0, 0.12)" + }, + "typography": { + "fontFamily": "Roboto, sans-serif", + "fontSize": { + "small": "12px", + "medium": "14px", + "large": "16px", + "xlarge": "20px" + }, + "codeFont": "JetBrains Mono, monospace" + }, + "borderRadius": { + "small": "2px", + "medium": "4px", + "large": "8px", + "card": "8px" + } +} diff --git a/packages/lua_test/components/ui.json b/packages/lua_test/components/ui.json new file mode 100644 index 000000000..b5e1e209f --- /dev/null +++ b/packages/lua_test/components/ui.json @@ -0,0 +1,223 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script-components.schema.json", + "schemaVersion": "2.0.0", + "package": "lua_test", + "description": "Lua testing framework UI components for test execution and results display", + "components": [ + { + "id": "test_runner", + "name": "TestRunner", + "description": "Interactive test runner component for executing Lua tests", + "props": [ + { + "name": "packageId", + "type": "string", + "required": true, + "description": "Package ID to test" + }, + { + "name": "autoRun", + "type": "boolean", + "required": false, + "default": false, + "description": "Automatically run tests on mount" + }, + { + "name": "filter", + "type": "string", + "required": false, + "description": "Filter tests by name pattern" + }, + { + "name": "verbose", + "type": "boolean", + "required": false, + "default": true, + "description": "Show verbose output" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "test-runner", + "children": [ + { + "type": "CardHeader", + "title": "Test Runner", + "subheader": "Package: {{packageId}}", + "action": { + "type": "IconButton", + "onClick": "{{onRun}}", + "children": [ + { + "type": "Icon", + "name": "PlayArrow", + "color": "primary" + } + ] + } + }, + { + "type": "CardContent", + "children": [ + { + "type": "Stack", + "spacing": 2, + "children": [ + { + "type": "TextField", + "label": "Filter", + "placeholder": "Filter tests by name...", + "value": "{{filter}}", + "onChange": "{{onFilterChange}}", + "size": "small", + "fullWidth": true + }, + { + "type": "FormControlLabel", + "control": { + "type": "Switch", + "checked": "{{verbose}}", + "onChange": "{{onVerboseChange}}" + }, + "label": "Verbose output" + }, + { + "type": "conditional", + "condition": "{{isRunning}}", + "then": { + "type": "LinearProgress", + "color": "primary" + } + } + ] + } + ] + } + ] + } + } + }, + { + "id": "test_results", + "name": "TestResults", + "description": "Displays test results in a formatted view with pass/fail indicators", + "props": [ + { + "name": "results", + "type": "object", + "required": true, + "description": "Test results object from runner" + }, + { + "name": "showDuration", + "type": "boolean", + "required": false, + "default": true, + "description": "Show test duration" + }, + { + "name": "expandErrors", + "type": "boolean", + "required": false, + "default": true, + "description": "Expand error details by default" + } + ], + "render": { + "type": "element", + "template": { + "type": "Card", + "variant": "outlined", + "className": "test-results", + "children": [ + { + "type": "CardHeader", + "title": "Test Results", + "subheader": "{{results.summary}}" + }, + { + "type": "CardContent", + "children": [ + { + "type": "Stack", + "spacing": 1, + "children": [ + { + "type": "Box", + "className": "results-summary", + "children": [ + { + "type": "Flex", + "gap": 2, + "children": [ + { + "type": "Chip", + "label": "{{results.passed}} passed", + "color": "success", + "size": "small" + }, + { + "type": "Chip", + "label": "{{results.failed}} failed", + "color": "error", + "size": "small" + }, + { + "type": "conditional", + "condition": "{{showDuration}}", + "then": { + "type": "Chip", + "label": "{{results.duration}}ms", + "variant": "outlined", + "size": "small" + } + } + ] + } + ] + }, + { + "type": "Divider" + }, + { + "type": "List", + "dense": true, + "children": { + "type": "for_each", + "items": "{{results.tests}}", + "as": "test", + "render": { + "type": "ListItem", + "children": [ + { + "type": "ListItemIcon", + "children": [ + { + "type": "Icon", + "name": "{{test.status === 'passed' ? 'CheckCircle' : 'Cancel'}}", + "color": "{{test.status === 'passed' ? 'success' : 'error'}}" + } + ] + }, + { + "type": "ListItemText", + "primary": "{{test.name}}", + "secondary": "{{test.duration}}ms" + } + ] + } + } + } + ] + } + ] + } + ] + } + } + } + ] +} diff --git a/packages/lua_test/package.json b/packages/lua_test/package.json new file mode 100644 index 000000000..d3365767b --- /dev/null +++ b/packages/lua_test/package.json @@ -0,0 +1,45 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-metadata.schema.json", + "packageId": "lua_test", + "name": "Lua Test", + "version": "1.0.0", + "description": "Unit testing framework for Lua scripts in MetaBuilder packages", + "author": "MetaBuilder", + "license": "MIT", + "category": "tools", + "minLevel": 3, + "primary": false, + "icon": "static_content/icon.svg", + "keywords": [ + "testing", + "lua", + "unit-test", + "framework", + "assertions", + "mocks" + ], + "dependencies": {}, + "devDependencies": {}, + "exports": { + "components": [ + "TestRunner", + "TestResults" + ], + "scripts": [ + "framework", + "runner", + "assertions", + "mocks" + ] + }, + "tests": { + "scripts": [ + "tests/metadata.test.lua" + ], + "parameterized": [ + { + "parameters": "tests/metadata.cases.json" + } + ] + } +} diff --git a/packages/lua_test/permissions/roles.json b/packages/lua_test/permissions/roles.json new file mode 100644 index 000000000..5ae227ea3 --- /dev/null +++ b/packages/lua_test/permissions/roles.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://metabuilder.dev/schemas/permissions.schema.json", + "schemaVersion": "1.0.0", + "package": "lua_test", + "description": "Lua test framework access permissions", + "permissions": [ + { + "id": "lua.test.run", + "name": "Run Lua Tests", + "description": "Execute Lua test suites", + "resource": "lua_test", + "action": "execute", + "scope": "global", + "minLevel": 3 + }, + { + "id": "lua.test.view", + "name": "View Test Results", + "description": "View test results and reports", + "resource": "lua_test", + "action": "read", + "scope": "global", + "minLevel": 3 + }, + { + "id": "lua.test.configure", + "name": "Configure Test Runner", + "description": "Configure test runner settings and filters", + "resource": "lua_test", + "action": "configure", + "scope": "global", + "minLevel": 4 + }, + { + "id": "lua.test.debug", + "name": "Debug Tests", + "description": "Access detailed debug output and error traces", + "resource": "lua_test", + "action": "debug", + "scope": "global", + "minLevel": 4 + } + ], + "resources": [ + { + "id": "lua_test", + "name": "Lua Test Framework", + "type": "tool", + "description": "Lua unit testing framework resources", + "actions": ["read", "execute", "configure", "debug"] + } + ] +} diff --git a/packages/lua_test/scripts/functions.json b/packages/lua_test/scripts/functions.json new file mode 100644 index 000000000..483526b99 --- /dev/null +++ b/packages/lua_test/scripts/functions.json @@ -0,0 +1,228 @@ +{ + "$schema": "https://metabuilder.dev/schemas/json-script.schema.json", + "schemaVersion": "2.2.0", + "package": "lua_test", + "description": "Lua unit testing framework functions including assertions, mocks, and test runner", + "functions": [ + { + "id": "framework_load_cases", + "name": "loadCases", + "exported": true, + "description": "Load test cases from JSON content", + "category": "core", + "luaScript": "framework.lua" + }, + { + "id": "framework_create_suite", + "name": "createSuite", + "exported": true, + "description": "Create a new test suite", + "category": "core", + "luaScript": "framework.lua" + }, + { + "id": "describe_it", + "name": "describe", + "exported": true, + "description": "BDD-style describe block for grouping tests", + "category": "core", + "luaScript": "describe.lua" + }, + { + "id": "describe_it_case", + "name": "it", + "exported": true, + "description": "BDD-style it block for individual test cases", + "category": "core", + "luaScript": "describe.lua" + }, + { + "id": "assertions_expect", + "name": "expect", + "exported": true, + "description": "Chainable assertion builder", + "category": "assertions", + "luaScript": "assertions.lua" + }, + { + "id": "assertions_true", + "name": "assertTrue", + "exported": true, + "description": "Assert value is truthy", + "category": "assertions", + "luaScript": "assertions.lua" + }, + { + "id": "assertions_false", + "name": "assertFalse", + "exported": true, + "description": "Assert value is falsy", + "category": "assertions", + "luaScript": "assertions.lua" + }, + { + "id": "assertions_equal", + "name": "assertEqual", + "exported": true, + "description": "Assert two values are equal", + "category": "assertions", + "luaScript": "assertions.lua" + }, + { + "id": "assertions_not_equal", + "name": "assertNotEqual", + "exported": true, + "description": "Assert two values are not equal", + "category": "assertions", + "luaScript": "assertions.lua" + }, + { + "id": "assertions_nil", + "name": "assertNil", + "exported": true, + "description": "Assert value is nil", + "category": "assertions", + "luaScript": "assertions.lua" + }, + { + "id": "assertions_not_nil", + "name": "assertNotNil", + "exported": true, + "description": "Assert value is not nil", + "category": "assertions", + "luaScript": "assertions.lua" + }, + { + "id": "mocks_fn", + "name": "fn", + "exported": true, + "description": "Create a mock function", + "category": "mocks", + "luaScript": "mocks.lua" + }, + { + "id": "mocks_spy_on", + "name": "spyOn", + "exported": true, + "description": "Spy on an object method", + "category": "mocks", + "luaScript": "mocks.lua" + }, + { + "id": "mocks_mock_object", + "name": "mockObject", + "exported": true, + "description": "Create a mock object", + "category": "mocks", + "luaScript": "mocks.lua" + }, + { + "id": "mocks_fake_timers", + "name": "useFakeTimers", + "exported": true, + "description": "Mock timer functions for testing async code", + "category": "mocks", + "luaScript": "mocks.lua" + }, + { + "id": "runner_run_test", + "name": "runTest", + "exported": true, + "description": "Run a single test", + "category": "runner", + "luaScript": "runner.lua" + }, + { + "id": "runner_run_suite", + "name": "runSuite", + "exported": true, + "description": "Run all tests in a suite", + "category": "runner", + "luaScript": "runner.lua" + }, + { + "id": "runner_run_all", + "name": "runAll", + "exported": true, + "description": "Run all registered test suites", + "category": "runner", + "luaScript": "runner.lua" + }, + { + "id": "runner_format_report", + "name": "formatReport", + "exported": true, + "description": "Format test results as human-readable report", + "category": "runner", + "luaScript": "runner.lua" + }, + { + "id": "runner_format_json", + "name": "formatJSON", + "exported": true, + "description": "Format test results as JSON", + "category": "runner", + "luaScript": "runner.lua" + }, + { + "id": "hooks_before_all", + "name": "beforeAll", + "exported": true, + "description": "Run setup before all tests in suite", + "category": "hooks", + "luaScript": "hooks.lua" + }, + { + "id": "hooks_after_all", + "name": "afterAll", + "exported": true, + "description": "Run teardown after all tests in suite", + "category": "hooks", + "luaScript": "hooks.lua" + }, + { + "id": "hooks_before_each", + "name": "beforeEach", + "exported": true, + "description": "Run setup before each test", + "category": "hooks", + "luaScript": "hooks.lua" + }, + { + "id": "hooks_after_each", + "name": "afterEach", + "exported": true, + "description": "Run teardown after each test", + "category": "hooks", + "luaScript": "hooks.lua" + } + ], + "exports": { + "functions": [ + "loadCases", + "createSuite", + "describe", + "it", + "expect", + "assertTrue", + "assertFalse", + "assertEqual", + "assertNotEqual", + "assertNil", + "assertNotNil", + "fn", + "spyOn", + "mockObject", + "useFakeTimers", + "runTest", + "runSuite", + "runAll", + "formatReport", + "formatJSON", + "beforeAll", + "afterAll", + "beforeEach", + "afterEach" + ] + } +} diff --git a/packages/lua_test/storybook/stories.json b/packages/lua_test/storybook/stories.json new file mode 100644 index 000000000..6cf2dc0c0 --- /dev/null +++ b/packages/lua_test/storybook/stories.json @@ -0,0 +1,162 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-storybook.schema.json", + "featured": false, + "title": "Lua Test Framework", + "description": "Unit testing framework components for Lua scripts", + "stories": [ + { + "name": "TestRunner", + "render": "framework", + "description": "Interactive test runner for executing Lua test suites", + "args": { + "packageId": "dashboard", + "autoRun": false, + "filter": "", + "verbose": true + } + }, + { + "name": "TestRunnerAutoRun", + "render": "framework", + "description": "Test runner with auto-run enabled", + "args": { + "packageId": "dashboard", + "autoRun": true, + "filter": "", + "verbose": true + } + }, + { + "name": "TestRunnerFiltered", + "render": "framework", + "description": "Test runner with name filter applied", + "args": { + "packageId": "dashboard", + "autoRun": false, + "filter": "stats", + "verbose": false + } + }, + { + "name": "TestResultsPassed", + "render": "results", + "description": "Test results showing all tests passed", + "args": { + "results": { + "summary": "All tests passed", + "passed": 5, + "failed": 0, + "duration": 42, + "tests": [ + { "name": "should calculate stats", "status": "passed", "duration": 8 }, + { "name": "should format values", "status": "passed", "duration": 5 }, + { "name": "should handle empty data", "status": "passed", "duration": 12 }, + { "name": "should compute trends", "status": "passed", "duration": 9 }, + { "name": "should validate input", "status": "passed", "duration": 8 } + ] + }, + "showDuration": true, + "expandErrors": false + } + }, + { + "name": "TestResultsMixed", + "render": "results", + "description": "Test results with some failures", + "args": { + "results": { + "summary": "2 of 5 tests failed", + "passed": 3, + "failed": 2, + "duration": 67, + "tests": [ + { "name": "should calculate stats", "status": "passed", "duration": 8 }, + { "name": "should format values", "status": "failed", "duration": 15, "error": "Expected '1,234' but got '1234'" }, + { "name": "should handle empty data", "status": "passed", "duration": 12 }, + { "name": "should compute trends", "status": "failed", "duration": 22, "error": "Assertion failed: expected up, got down" }, + { "name": "should validate input", "status": "passed", "duration": 10 } + ] + }, + "showDuration": true, + "expandErrors": true + } + }, + { + "name": "TestResultsFailed", + "render": "results", + "description": "Test results showing all tests failed", + "args": { + "results": { + "summary": "All tests failed", + "passed": 0, + "failed": 3, + "duration": 34, + "tests": [ + { "name": "should initialize framework", "status": "failed", "duration": 12, "error": "Module not found: suite" }, + { "name": "should create suite", "status": "failed", "duration": 11, "error": "Dependency error" }, + { "name": "should run tests", "status": "failed", "duration": 11, "error": "Framework not initialized" } + ] + }, + "showDuration": true, + "expandErrors": true + } + } + ], + "renders": { + "framework": { + "description": "Test runner component", + "featured": true + }, + "results": { + "description": "Test results display" + } + }, + "defaultContext": { + "user": { + "id": "dev-user", + "username": "developer", + "level": 3, + "email": "dev@example.com" + }, + "tenant": { + "id": "demo-tenant", + "name": "Development Environment" + } + }, + "contextVariants": [ + { + "name": "Developer", + "description": "Can run and view tests", + "context": { + "user": { + "username": "developer", + "level": 3 + } + } + }, + { + "name": "Admin", + "description": "Can run, view, and configure tests", + "context": { + "user": { + "username": "admin", + "level": 4 + } + } + } + ], + "scripts": { + "renderFunctions": ["framework", "results"], + "ignoredScripts": ["tests", "helpers"] + }, + "parameters": { + "layout": "padded", + "backgrounds": { + "default": "light", + "values": [ + { "name": "light", "value": "#f5f5f5" }, + { "name": "dark", "value": "#1a1a1a" } + ] + } + } +} diff --git a/packages/lua_test/styles/tokens.json b/packages/lua_test/styles/tokens.json new file mode 100644 index 000000000..df0f96e52 --- /dev/null +++ b/packages/lua_test/styles/tokens.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://metabuilder.dev/schemas/package-styles.schema.json", + "schemaVersion": "2.0.0", + "colors": { + "testPassed": "#28a745", + "testFailed": "#dc3545", + "testSkipped": "#ffc107", + "testPending": "#6c757d", + "testRunning": "#007bff", + "assertionSuccess": "#28a745", + "assertionFailure": "#dc3545", + "mockHighlight": "#6f42c1", + "codeBg": "#f8f9fa", + "errorBg": "#fff5f5", + "successBg": "#f0fff4" + }, + "spacing": { + "testResultPadding": "12px", + "testItemGap": "8px", + "suiteIndent": "16px", + "assertionIndent": "24px", + "errorStackPadding": "8px" + }, + "shadows": { + "testCard": "0 2px 8px rgba(0, 0, 0, 0.1)", + "resultPanel": "0 1px 4px rgba(0, 0, 0, 0.08)", + "errorHighlight": "inset 3px 0 0 #dc3545" + }, + "typography": { + "testName": { + "fontFamily": "IBM Plex Sans", + "fontSize": "14px", + "fontWeight": 500 + }, + "suiteName": { + "fontFamily": "Space Grotesk", + "fontSize": "16px", + "fontWeight": 600 + }, + "errorMessage": { + "fontFamily": "JetBrains Mono", + "fontSize": "12px", + "fontWeight": 400 + }, + "codeBlock": { + "fontFamily": "JetBrains Mono", + "fontSize": "13px", + "lineHeight": 1.5 + } + }, + "borders": { + "testItem": "1px solid #dee2e6", + "suiteHeader": "2px solid #007bff", + "errorBlock": "1px solid #dc3545" + } +}