Conversation
…, brandfetch, google meet
|
Too many files changed for review. ( |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryLow Risk Overview Improves OpenAPI reference layout and method-badge styling by switching to grid named lines, adding Expands documentation content: adds a new Knowledge Base Written by Cursor Bugbot for commit 8dbdebd. This will update automatically on new commits. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Non-copilot sources misattributed to copilot billing counters
- Added conditional check to only increment copilot-specific counters (totalCopilotCost, currentPeriodCopilotCost, totalCopilotCalls, totalCopilotTokens) when source is 'copilot' or 'mcp_copilot', preventing workspace-chat and mothership_block costs from being misattributed.
- ✅ Fixed: Duplicated
hexToRgbautility across landing components- Extracted the hexToRgba function to a shared utility at lib/core/utils/color.ts and updated both features.tsx and templates.tsx to import from the shared location.
Or push these changes by commenting:
@cursor push a1b4fb2499
Preview (a1b4fb2499)
diff --git a/apps/sim/app/(home)/components/features/features.tsx b/apps/sim/app/(home)/components/features/features.tsx
--- a/apps/sim/app/(home)/components/features/features.tsx
+++ b/apps/sim/app/(home)/components/features/features.tsx
@@ -3,14 +3,8 @@
import { useState } from 'react'
import Image from 'next/image'
import { Badge } from '@/components/emcn'
+import { hexToRgba } from '@/lib/core/utils/color'
-function hexToRgba(hex: string, alpha: number): string {
- const r = Number.parseInt(hex.slice(1, 3), 16)
- const g = Number.parseInt(hex.slice(3, 5), 16)
- const b = Number.parseInt(hex.slice(5, 7), 16)
- return `rgba(${r},${g},${b},${alpha})`
-}
-
const FEATURE_TABS = [
{
label: 'Integrations',
diff --git a/apps/sim/app/(home)/components/templates/templates.tsx b/apps/sim/app/(home)/components/templates/templates.tsx
--- a/apps/sim/app/(home)/components/templates/templates.tsx
+++ b/apps/sim/app/(home)/components/templates/templates.tsx
@@ -6,6 +6,7 @@
import Link from 'next/link'
import { Badge, ChevronDown } from '@/components/emcn'
import { cn } from '@/lib/core/utils/cn'
+import { hexToRgba } from '@/lib/core/utils/color'
import { TEMPLATE_WORKFLOWS } from '@/app/(home)/components/templates/template-workflows'
const LandingPreviewWorkflow = dynamic(
@@ -19,13 +20,6 @@
}
)
-function hexToRgba(hex: string, alpha: number): string {
- const r = Number.parseInt(hex.slice(1, 3), 16)
- const g = Number.parseInt(hex.slice(3, 5), 16)
- const b = Number.parseInt(hex.slice(5, 7), 16)
- return `rgba(${r},${g},${b},${alpha})`
-}
-
const LEFT_WALL_CLIP = 'polygon(0 8px, 100% 0, 100% 100%, 0 100%)'
const BOTTOM_WALL_CLIP = 'polygon(0 0, 100% 0, calc(100% - 8px) 100%, 0 100%)'
diff --git a/apps/sim/app/api/billing/update-cost/route.ts b/apps/sim/app/api/billing/update-cost/route.ts
--- a/apps/sim/app/api/billing/update-cost/route.ts
+++ b/apps/sim/app/api/billing/update-cost/route.ts
@@ -78,6 +78,7 @@
}
const { userId, cost, model, inputTokens, outputTokens, source } = validation.data
+ const isCopilot = source === 'copilot' || source === 'mcp_copilot'
const isMcp = source === 'mcp_copilot'
logger.info(`[${requestId}] Processing cost update`, {
@@ -105,13 +106,16 @@
const updateFields: Record<string, unknown> = {
totalCost: sql`total_cost + ${cost}`,
currentPeriodCost: sql`current_period_cost + ${cost}`,
- totalCopilotCost: sql`total_copilot_cost + ${cost}`,
- currentPeriodCopilotCost: sql`current_period_copilot_cost + ${cost}`,
- totalCopilotCalls: sql`total_copilot_calls + 1`,
- totalCopilotTokens: sql`total_copilot_tokens + ${totalTokens}`,
lastActive: new Date(),
}
+ if (isCopilot) {
+ updateFields.totalCopilotCost = sql`total_copilot_cost + ${cost}`
+ updateFields.currentPeriodCopilotCost = sql`current_period_copilot_cost + ${cost}`
+ updateFields.totalCopilotCalls = sql`total_copilot_calls + 1`
+ updateFields.totalCopilotTokens = sql`total_copilot_tokens + ${totalTokens}`
+ }
+
if (isMcp) {
updateFields.totalMcpCopilotCost = sql`total_mcp_copilot_cost + ${cost}`
updateFields.currentPeriodMcpCopilotCost = sql`current_period_mcp_copilot_cost + ${cost}`
diff --git a/apps/sim/lib/core/utils/color.ts b/apps/sim/lib/core/utils/color.ts
new file mode 100644
--- /dev/null
+++ b/apps/sim/lib/core/utils/color.ts
@@ -1,0 +1,12 @@
+/**
+ * Converts a hex color string to an rgba string with the specified alpha.
+ * @param hex - Hex color string (e.g., '#FF0000')
+ * @param alpha - Alpha value between 0 and 1
+ * @returns An rgba color string (e.g., 'rgba(255,0,0,0.5)')
+ */
+export function hexToRgba(hex: string, alpha: number): string {
+ const r = Number.parseInt(hex.slice(1, 3), 16)
+ const g = Number.parseInt(hex.slice(3, 5), 16)
+ const b = Number.parseInt(hex.slice(5, 7), 16)
+ return `rgba(${r},${g},${b},${alpha})`
+}| const g = Number.parseInt(hex.slice(3, 5), 16) | ||
| const b = Number.parseInt(hex.slice(5, 7), 16) | ||
| return `rgba(${r},${g},${b},${alpha})` | ||
| } |
There was a problem hiding this comment.
Duplicated hexToRgba utility across landing components
Low Severity
The hexToRgba function is identically defined in both features.tsx and templates.tsx. This duplicated logic increases maintenance burden — a bug fix in one copy could easily be missed in the other. It could be extracted to a shared utility.
Additional Locations (1)
… pagination, memory improvements
* feat(api): add tables and files v1 REST API with OpenAPI docs * fix(api): address review feedback for tables/files REST API * fix(api): reject empty filters, consolidate PUT/DELETE into service helpers * fix(api): upsert unique constraints, POST response fields, uploadedAt timestamp * fix(api): stop leaking internal fields in list tables, fix deleteTable requestId * fix(api): atomic table-count limit in createTable, stop leaking internal fields * fix(api): error classification in PATCH, z.coerce→preprocess, requestId in logs * fix(api): audit logging, PATCH service consolidation, Content-Disposition encoding - Add TABLE_CREATED/TABLE_DELETED audit events to v1 table routes - Consolidate PATCH handlers to use updateRow service function - Fix Content-Disposition header with RFC 5987 dual-parameter form - Normalize schema in POST /tables response with normalizeColumn * lint * fix(api): upsert unique constraint 400, guard request.json() parse errors - Add 'Unique constraint violation' to upsert error classification - Wrap PUT/DELETE request.json() in try/catch to return 400 on malformed body - Apply fixes to both v1 and internal routes * fix(api): guard PATCH request.json(), accurate deleteRowsByIds count - Wrap PATCH request.json() in try/catch for both v1 and internal routes - Rewrite deleteRowsByIds to use .returning() for accurate deletedCount under concurrent requests (eliminates SELECT-then-DELETE race) * fix(api): guard all remaining request.json() calls in table routes - Wrap POST handler request.json() in try/catch across all table routes - Also fix internal DELETE single-row handler - Every request.json() in table routes now returns 400 on malformed body * fix(api): safe type check on formData workspaceId in file upload - Replace unsafe `as string | null` cast with typeof check - Prevents File object from bypassing workspaceId validation * fix(api): safe File cast in upload, validate column name before sql.raw() - Use instanceof File check instead of unsafe `as File | null` cast - Add regex validation on column name before sql.raw() interpolation * fix(api): comprehensive hardening pass across all table/file routes - Guard request.formData() with try/catch in file upload - Guard all .toISOString() calls with instanceof Date checks - Replace verifyTableWorkspace double-fetch with direct comparison - Fix relative imports to absolute (@/app/api/table/utils) - Fix internal list tables leaking fields via ...t spread - Normalize schema in internal POST create table response - Remove redundant pre-check in internal create (service handles atomically) - Make 'maximum table limit' return 403 consistently (was 400 in internal) - Add 'Row not found' → 404 classification in PATCH handlers - Add NAME_PATTERN validation before sql.raw() in validation.ts * chore: lint fixes
Use sessionStorage to store the return URL when entering settings, and use router.replace for tab switches so history doesn't accumulate. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…t stuck schedules Multiple error/early-return paths in executeScheduleJob and executeJobInline were exiting without clearing lastQueuedAt, causing the dueFilter to permanently skip those schedules — resulting in stale "X hours ago" display for nextRunAt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…name tool - Add double-click inline rename on file and table resource tabs - Wire useInlineRename + useRenameWorkspaceFile/useRenameTable mutations - Add rename operation to workspace_file copilot tool (schema, server, router) - Add knowledge base resource support (type, extraction, rendering, actions) - Accept optional className on InlineRenameInput for context-specific sizing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keep the workspace_file rename tool for the mothership agent. Only the UI-side inline rename (double-click tabs) is removed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rceTable refactor - Extract KB resources from knowledge subagent respond format (knowledge_bases array) - Add knowledge_base tool to RESOURCE_TOOL_NAMES and TOOL_UI_METADATA - Extract ResourceTable as independently composable memoized component - Move contentOverride/overlay to Resource shell level (not table primitive) - Remove redundant disableHeaderSort and loadingRows props - Rename internal sort state for clarity (sort → internalSort, sortOverride → externalSort) - Export ResourceTable and ResourceTableProps from barrel Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…3529) * Run workflows client side in mothership to transmit logs * Initialize set as constant, prevent duplicate execution * Fix lint --------- Co-authored-by: Theodore Li <theo@sim.ai>
* Hide resources that have been deleted * Handle table, workflow not found * Add animation to prevent flash when previous resource was deleted * Fix animation playing on every switch * Run workflows client side in mothership to transmit logs * Fix race condition for animation * Use shared workflow tool util file --------- Co-authored-by: Theodore Li <theo@sim.ai>
…into feat/mothership-copilot
Remove delete operations for workflows, folders, tables, and files from the mothership copilot to prevent destructive actions via AI. Row-level and column-level deletes are preserved. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…3540) The sidebar was forcibly collapsed whenever a resource (e.g. workflow) first appeared in the resource panel during a task. This was disruptive on larger screens where users want to keep both the sidebar and resource panel visible simultaneously. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mothership): remove resource-level delete tools from copilot Remove delete operations for workflows, folders, tables, and files from the mothership copilot to prevent destructive actions via AI. Row-level and column-level deletes are preserved. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(mothership): insert copilot-created workflows at top of list * fix(mothership): server-side top-insertion sort order and deduplicate registry logic * fix(mothership): include folder sort orders when computing top-insertion position * fix(mothership): use getNextWorkflowColor instead of hardcoded color --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
#3538) * Connect play stop workflow in embedded view to workflow * Fix stop not actually stoping workflow * Fix ui not showing stopped by user * Lint fix * Plumb cancellation through system * Stopping mothership chat stops workflow * Remove extra fluff * Persist blocks on cancellation * Add root level stopped by user --------- Co-authored-by: Theodore Li <theo@sim.ai>
* fix(autolayout): targetted autolayout heuristic restored * fix autolayout boundary cases * more fixes * address comments * on conflict updates * address more comments * fix relative position scope * fix tye omission * address bugbot comment
) * feat(mothership): server-persisted unread task indicators via SSE Replace fragile client-side polling + timer-based green flash with server-persisted lastSeenAt semantics, real-time SSE push via Redis pub/sub, and dot overlay UI on the Blimp icon. - Add lastSeenAt column to copilotChats for server-persisted read state - Add Redis/local pub/sub singleton for task status events (started, completed, created, deleted, renamed) - Add SSE endpoint (GET /api/mothership/events) with heartbeat and workspace-scoped filtering - Add mark-read endpoint (POST /api/mothership/chats/read) - Publish SSE events from chat, rename, delete, and auto-title handlers - Add useTaskEvents hook for client-side SSE subscription - Add useMarkTaskRead mutation with optimistic update - Replace timer logic in sidebar with TaskStatus state machine (running/unread/idle) and dot overlay using brand color variables - Mark tasks read on mount and stream completion in home page - Fix security: add userId check to delete WHERE clause - Fix: bump updatedAt on stream completion - Fix: set lastSeenAt on rename to prevent false-positive unread Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review feedback - Return 404 when delete finds no matching chat (was silent no-op) - Move log after ownership check so it only fires on actual deletion - Publish completed SSE event from stop route so sidebar dot clears on abort Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: backfill last_seen_at in migration to prevent false unread dots Existing rows would have last_seen_at = NULL after migration, causing all past completed tasks to show as unread. Backfill sets last_seen_at to updated_at for all existing rows. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: timestamp mismatch on task creation + wasSendingRef leak across navigation - Pass updatedAt explicitly alongside lastSeenAt on chat creation so both use the same JS timestamp (DB defaultNow() ran later, causing updatedAt > lastSeenAt → false unread) - Reset wasSendingRef when chatId changes to prevent a stale true from task A triggering a redundant markRead on task B Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: mark-read fires for inline-created chats + encode workspaceId in SSE URL Expose resolvedChatId from useChat so home.tsx can mark-read even when chatId prop stays undefined after replaceState URL update. Also URL-encode workspaceId in EventSource URL as a defensive measure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: auto-focus home input on initial view + fix sidebar task click handling Auto-focus the textarea when the initial home view renders. Also fix sidebar task click to always call onMultiSelectClick so selection state stays consistent. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: auto-title sets lastSeenAt + move started event inside DB guard Auto-title now sets both updatedAt and lastSeenAt (matching the rename route pattern) to prevent false-positive unread dots. Also move the 'started' SSE event inside the if(updated) guard so it only fires when the DB update actually matched a row. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * modified tasks multi select to be just like workflows * fix * refactor: extract generic pub/sub and SSE factories + fixes - Extract createPubSubChannel factory (lib/events/pubsub.ts) to eliminate duplicated Redis/EventEmitter boilerplate between task and MCP pub/sub - Extract createWorkspaceSSE factory (lib/events/sse-endpoint.ts) to share auth, heartbeat, and cleanup logic across SSE endpoints - Fix auto-title race suppressing unread status by removing updatedAt/lastSeenAt from title-only DB update - Fix wheel event listener leak in ResourceTabs (RefCallback cleanup was silently discarded) - Fix getFullSelection() missing taskIds (inconsistent with hasAnySelection) - Deduplicate SSE_RESPONSE_HEADERS to spread from shared SSE_HEADERS - Hoist isSttAvailable to module-level constant to avoid per-render IIFE Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Make resources persist to backend * Use colored squares for workflows * Add click and drag functionality to resource * Fix expanding panel logic * Reduce duplication, reading resource also opens up resource panel * Move resource dropdown to own file * Handle renamed resources * Clicking already open tab should just switch to tab --------- Co-authored-by: Theodore Li <theo@sim.ai>
* feat(context) add currenttly open resource file to context for agent * Simplify resource resolution * Skip initialize vfs * Restore ff * Add back try catch * Remove redundant code * Remove json serialization/deserialization loop --------- Co-authored-by: Theodore Li <theo@sim.ai>
* feat(chat) add at sign * Address bugbot issues * Remove extra chatcontext defs * Add table and file to schema * Add icon to chip for files --------- Co-authored-by: Theodore Li <theo@sim.ai>
…ty improvements (#3561) * improvement(deletion): migrate to soft deletion of resources * progress * scoping fixes * round of fixes * deduplicated name on workflow import * fix tests * add migration * cleanup dead code * address bugbot comments * optimize query
…an gating (#3558) * feat(sim-mailer): email inbox for mothership with chat history and plan gating * revert hardcoded ff * fix(inbox): address PR review comments - plan enforcement, idempotency, webhook auth - Enforce Max plan at API layer: hasInboxAccess() now checks subscription tier (>= 25k credits or enterprise) - Add idempotency guard to executeInboxTask() to prevent duplicate emails on Trigger.dev retries - Add AGENTMAIL_WEBHOOK_SECRET env var for webhook signature verification (Bearer token) * improvement(inbox): harden security and efficiency from code audit - Use crypto.timingSafeEqual for webhook secret comparison (prevents timing attacks) - Atomic claim in executor: WHERE status='received' prevents duplicate processing on retries - Parallelize hasInboxAccess + getUserEntityPermissions in all API routes (reduces latency) - Truncate email body at webhook insertion (50k char limit, prevents unbounded DB storage) - Harden escapeAttr with angle bracket and single quote escaping - Rename use-inbox.ts to inbox.ts (matches hooks/queries/ naming convention) * fix(inbox): replace Bearer token auth with proper Svix HMAC-SHA256 webhook verification - Use per-workspace webhook secret from DB instead of global env var - Verify AgentMail/Svix signatures: HMAC-SHA256 over svix-id.timestamp.body - Timing-safe comparison via crypto.timingSafeEqual - Replay protection via timestamp tolerance (5 min window) - Join mothershipInboxWebhook in workspace lookup (zero additional DB calls) - Remove dead AGENTMAIL_WEBHOOK_SECRET env var - Select only needed workspace columns in webhook handler * fix(inbox): require webhook secret — reject requests when secret is missing Previously, if the webhook secret was missing from the DB (corrupted state), the handler would skip verification entirely and process the request unauthenticated. Now all three conditions are hard requirements: secret must exist in DB, Svix headers must be present, and signature must verify. * fix(inbox): address second round of PR review comments - Exclude rejected tasks from rate limit count to prevent DoS via spam - Strip raw HTML from LLM output before marked.parse to prevent XSS in emails - Track responseSent flag to prevent duplicate emails when DB update fails after send * fix(inbox): address third round of PR review comments - Use dynamic isHosted from feature-flags instead of hardcoded true - Atomic JSON append for chat message persistence (eliminates read-modify-write race) - Handle cutIndex === 0 in stripQuotedReply (body starts with quote) - Clean up orphan mothershipInboxWebhook row on enableInbox rollback - Validate status query parameter against enum in tasks API * fix(inbox): validate cursor param, preserve code blocks in HTML stripping - Validate cursor date before using in query (return 400 for invalid) - Split on fenced code blocks before stripping HTML tags to preserve code examples in email responses * fix(inbox): return 500 on webhook server errors to enable Svix retries * fix(inbox): remove isHosted guard from hasInboxAccess — feature flag is sufficient * fix(inbox): prevent double-enable from deleting webhook secret row * fix(inbox): null-safe stripThinkingTags, encode URL params, surface remove-sender errors - Guard against null result.content in stripThinkingTags - Use encodeURIComponent on all AgentMail API path parameters - Surface handleRemoveSender errors to the user instead of swallowing * improvement(inbox): remove unused types, narrow SELECT queries, fix optimistic ID collision Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(inbox): add keyboard accessibility to clickable task rows * fix(inbox): use Svix library for webhook verification, fix responseSent flag, prevent inbox enumeration - Replace manual HMAC-SHA256 verification with official Svix library per AgentMail docs - Fix responseSent flag: only set true when email delivery actually succeeds - Return consistent 401 for unknown inbox and bad signature to prevent enumeration - Make AgentMailInbox.organization_id optional to match API docs * chore(db): rebase inbox migration onto feat/mothership-copilot (0172 → 0173) Sync schema with target branch and regenerate migration as 0173 to avoid conflicts with 0172_silky_magma on feat/mothership-copilot. * fix(db): rebase inbox migration to 0173 after feat/mothership-copilot divergence Target branch added 0172_silky_magma, so our inbox migration is now 0173_youthful_stryfe. * fix(db): regenerate inbox migration after rebase on feat/mothership-copilot * fix(inbox): case-insensitive email match and sanitize javascript: URIs in email HTML - Use lower() in isSenderAllowed SQL to match workspace members regardless of email case stored by auth provider - Strip javascript:, vbscript:, and data: URIs from marked HTML output to prevent XSS in outbound email responses * fix(inbox): case-insensitive email match in resolveUserId Consistent with the isSenderAllowed fix — uses lower() so mixed-case stored emails match correctly, preventing silent fallback to workspace owner. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>



Summary
Brief description of what this PR does and why.
Fixes #(issue)
Type of Change
Testing
How has this been tested? What should reviewers focus on?
Checklist
Screenshots/Videos