diff --git a/.claude/rules/global.md b/.claude/rules/global.md index e749b67b286..b80c3695ce3 100644 --- a/.claude/rules/global.md +++ b/.claude/rules/global.md @@ -9,5 +9,26 @@ Use TSDoc for documentation. No `====` separators. No non-TSDoc comments. ## Styling Never update global styles. Keep all styling local to components. +## ID Generation +Never use `crypto.randomUUID()`, `nanoid`, or the `uuid` package directly. Use the utilities from `@/lib/core/utils/uuid`: + +- `generateId()` — UUID v4, use by default +- `generateShortId(size?)` — short URL-safe ID (default 21 chars), for compact identifiers + +Both use `crypto.getRandomValues()` under the hood and work in all contexts including non-secure (HTTP) browsers. + +```typescript +// ✗ Bad +import { nanoid } from 'nanoid' +import { v4 as uuidv4 } from 'uuid' +const id = crypto.randomUUID() + +// ✓ Good +import { generateId, generateShortId } from '@/lib/core/utils/uuid' +const uuid = generateId() +const shortId = generateShortId() +const tiny = generateShortId(8) +``` + ## Package Manager Use `bun` and `bunx`, not `npm` and `npx`. diff --git a/.cursor/rules/global.mdc b/.cursor/rules/global.mdc index b21c1577b61..af32f057955 100644 --- a/.cursor/rules/global.mdc +++ b/.cursor/rules/global.mdc @@ -16,5 +16,26 @@ Use TSDoc for documentation. No `====` separators. No non-TSDoc comments. ## Styling Never update global styles. Keep all styling local to components. +## ID Generation +Never use `crypto.randomUUID()`, `nanoid`, or the `uuid` package directly. Use the utilities from `@/lib/core/utils/uuid`: + +- `generateId()` — UUID v4, use by default +- `generateShortId(size?)` — short URL-safe ID (default 21 chars), for compact identifiers + +Both use `crypto.getRandomValues()` under the hood and work in all contexts including non-secure (HTTP) browsers. + +```typescript +// ✗ Bad +import { nanoid } from 'nanoid' +import { v4 as uuidv4 } from 'uuid' +const id = crypto.randomUUID() + +// ✓ Good +import { generateId, generateShortId } from '@/lib/core/utils/uuid' +const uuid = generateId() +const shortId = generateShortId() +const tiny = generateShortId(8) +``` + ## Package Manager Use `bun` and `bunx`, not `npm` and `npx`. diff --git a/AGENTS.md b/AGENTS.md index 004252ac6a4..bc54c6f912c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,6 +7,7 @@ You are a professional software engineer. All code must follow best practices: a - **Logging**: Import `createLogger` from `@sim/logger`. Use `logger.info`, `logger.warn`, `logger.error` instead of `console.log` - **Comments**: Use TSDoc for documentation. No `====` separators. No non-TSDoc comments - **Styling**: Never update global styles. Keep all styling local to components +- **ID Generation**: Never use `crypto.randomUUID()`, `nanoid`, or `uuid` package. Use `generateId()` (UUID v4) or `generateShortId()` (compact) from `@/lib/core/utils/uuid` - **Package Manager**: Use `bun` and `bunx`, not `npm` and `npx` ## Architecture diff --git a/CLAUDE.md b/CLAUDE.md index 004252ac6a4..bc54c6f912c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,6 +7,7 @@ You are a professional software engineer. All code must follow best practices: a - **Logging**: Import `createLogger` from `@sim/logger`. Use `logger.info`, `logger.warn`, `logger.error` instead of `console.log` - **Comments**: Use TSDoc for documentation. No `====` separators. No non-TSDoc comments - **Styling**: Never update global styles. Keep all styling local to components +- **ID Generation**: Never use `crypto.randomUUID()`, `nanoid`, or `uuid` package. Use `generateId()` (UUID v4) or `generateShortId()` (compact) from `@/lib/core/utils/uuid` - **Package Manager**: Use `bun` and `bunx`, not `npm` and `npx` ## Architecture diff --git a/apps/docs/content/docs/en/blocks/response.mdx b/apps/docs/content/docs/en/blocks/response.mdx index 327bbaa6eb0..6ec1872fe14 100644 --- a/apps/docs/content/docs/en/blocks/response.mdx +++ b/apps/docs/content/docs/en/blocks/response.mdx @@ -20,7 +20,7 @@ The Response block formats and sends structured HTTP responses back to API calle - Response blocks are terminal blocks - they end workflow execution and cannot connect to other blocks. + Response blocks are exit points — when a Response block executes, it ends the workflow and sends the HTTP response immediately. Multiple Response blocks can be placed on different branches (e.g. after a Router or Condition), but only the first one to execute determines the API response. ## Configuration Options @@ -77,7 +77,11 @@ Condition (Error Detected) → Router → Response (400/500, Error Details) ## Outputs -Response blocks are terminal — no downstream blocks execute after them. However, the block does define outputs (`data`, `status`, `headers`) which are used to construct the HTTP response sent back to the API caller. +Response blocks are exit points — when one executes, no further blocks run. The block defines outputs (`data`, `status`, `headers`) which are used to construct the HTTP response sent back to the API caller. + + + If a Response block is placed on a parallel branch, there are no guarantees about whether other parallel blocks will run or not. Execution order across parallel branches is non-deterministic, so a parallel block may execute before or after the Response block on any given run. Avoid placing Response blocks in parallel with blocks that have important side effects. + ## Variable References @@ -110,10 +114,10 @@ Use the `` syntax to dynamically insert workflow variables into y - **Validate variable references**: Ensure all referenced variables exist and contain the expected data types before the Response block executes diff --git a/apps/docs/content/docs/en/execution/basics.mdx b/apps/docs/content/docs/en/execution/basics.mdx index 1541831e770..1777b7fdcfb 100644 --- a/apps/docs/content/docs/en/execution/basics.mdx +++ b/apps/docs/content/docs/en/execution/basics.mdx @@ -96,8 +96,9 @@ Understanding these core principles will help you build better workflows: 2. **Automatic Parallelization**: Independent blocks run concurrently without configuration 3. **Smart Data Flow**: Outputs flow automatically to connected blocks 4. **Error Handling**: Failed blocks stop their execution path but don't affect independent paths -5. **State Persistence**: All block outputs and execution details are preserved for debugging -6. **Cycle Protection**: Workflows that call other workflows (via Workflow blocks, MCP tools, or API blocks) are tracked with a call chain. If the chain exceeds 25 hops, execution is stopped to prevent infinite loops +5. **Response Blocks as Exit Points**: When a Response block executes, the entire workflow stops and the API response is sent immediately. Multiple Response blocks can exist on different branches — the first one to execute wins +6. **State Persistence**: All block outputs and execution details are preserved for debugging +7. **Cycle Protection**: Workflows that call other workflows (via Workflow blocks, MCP tools, or API blocks) are tracked with a call chain. If the chain exceeds 25 hops, execution is stopped to prevent infinite loops ## Next Steps diff --git a/apps/docs/content/docs/en/tools/cursor.mdx b/apps/docs/content/docs/en/tools/cursor.mdx index 09bcd4644f4..4e6f165c014 100644 --- a/apps/docs/content/docs/en/tools/cursor.mdx +++ b/apps/docs/content/docs/en/tools/cursor.mdx @@ -45,6 +45,7 @@ List all cloud agents for the authenticated user with optional pagination. Retur | `apiKey` | string | Yes | Cursor API key | | `limit` | number | No | Number of agents to return \(default: 20, max: 100\) | | `cursor` | string | No | Pagination cursor from previous response | +| `prUrl` | string | No | Filter agents by pull request URL | #### Output @@ -173,4 +174,41 @@ Permanently delete a cloud agent. Returns API-aligned fields only. | --------- | ---- | ----------- | | `id` | string | Agent ID | +### `cursor_list_artifacts` + +List generated artifact files for a cloud agent. Returns API-aligned fields only. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Cursor API key | +| `agentId` | string | Yes | Unique identifier for the cloud agent \(e.g., bc_abc123\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `artifacts` | array | List of artifact files | +| ↳ `path` | string | Artifact file path | +| ↳ `size` | number | File size in bytes | + +### `cursor_download_artifact` + +Download a generated artifact file from a cloud agent. Returns the file for execution storage. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Cursor API key | +| `agentId` | string | Yes | Unique identifier for the cloud agent \(e.g., bc_abc123\) | +| `path` | string | Yes | Absolute path of the artifact to download \(e.g., /src/index.ts\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `file` | file | Downloaded artifact file stored in execution files | + diff --git a/apps/sim/app/(auth)/auth-layout-client.tsx b/apps/sim/app/(auth)/auth-layout-client.tsx index 3aee420922f..89aeb3a89e7 100644 --- a/apps/sim/app/(auth)/auth-layout-client.tsx +++ b/apps/sim/app/(auth)/auth-layout-client.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react' import AuthBackground from '@/app/(auth)/components/auth-background' -import Navbar from '@/app/(home)/components/navbar/navbar' +import Navbar from '@/app/(landing)/components/navbar/navbar' export default function AuthLayoutClient({ children }: { children: React.ReactNode }) { useEffect(() => { diff --git a/apps/sim/app/(auth)/components/social-login-buttons.tsx b/apps/sim/app/(auth)/components/social-login-buttons.tsx index 3545840681e..bf1d112c504 100644 --- a/apps/sim/app/(auth)/components/social-login-buttons.tsx +++ b/apps/sim/app/(auth)/components/social-login-buttons.tsx @@ -81,7 +81,7 @@ export function SocialLoginButtons({ const githubButton = ( - - - Get started - - - - - - - - -
- - - - -
- -
-
- - - - ) -} diff --git a/apps/sim/app/(home)/components/index.ts b/apps/sim/app/(home)/components/index.ts deleted file mode 100644 index b05b10953e2..00000000000 --- a/apps/sim/app/(home)/components/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import Collaboration from '@/app/(home)/components/collaboration/collaboration' -import Enterprise from '@/app/(home)/components/enterprise/enterprise' -import Features from '@/app/(home)/components/features/features' -import Footer from '@/app/(home)/components/footer/footer' -import Hero from '@/app/(home)/components/hero/hero' -import Navbar from '@/app/(home)/components/navbar/navbar' -import Pricing from '@/app/(home)/components/pricing/pricing' -import StructuredData from '@/app/(home)/components/structured-data' -import Templates from '@/app/(home)/components/templates/templates' -import Testimonials from '@/app/(home)/components/testimonials/testimonials' - -export { - Collaboration, - Enterprise, - Features, - Footer, - Hero, - Navbar, - Pricing, - StructuredData, - Templates, - Testimonials, -} diff --git a/apps/sim/app/(home)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx deleted file mode 100644 index 3a7b88d2ff6..00000000000 --- a/apps/sim/app/(home)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx +++ /dev/null @@ -1,99 +0,0 @@ -'use client' - -import { memo, useCallback, useRef, useState } from 'react' -import { ArrowUp } from 'lucide-react' -import { useLandingSubmit } from '@/app/(home)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' -import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' - -const C = { - SURFACE: '#292929', - BORDER: '#3d3d3d', - TEXT_PRIMARY: '#e6e6e6', -} as const - -/** - * Landing preview replica of the workspace Home initial view. - * Shows a greeting heading and a minimal chat input (no + or mic). - * On submit, stores the prompt and redirects to /signup. - */ -export const LandingPreviewHome = memo(function LandingPreviewHome() { - const landingSubmit = useLandingSubmit() - const [inputValue, setInputValue] = useState('') - const textareaRef = useRef(null) - const animatedPlaceholder = useAnimatedPlaceholder() - - const isEmpty = inputValue.trim().length === 0 - - const handleSubmit = useCallback(() => { - if (isEmpty) return - landingSubmit(inputValue) - }, [isEmpty, inputValue, landingSubmit]) - - const MAX_HEIGHT = 200 - - const handleKeyDown = useCallback( - (e: React.KeyboardEvent) => { - if (e.key === 'Enter' && !e.shiftKey) { - e.preventDefault() - handleSubmit() - } - }, - [handleSubmit] - ) - - const handleInput = useCallback((e: React.FormEvent) => { - const target = e.target as HTMLTextAreaElement - target.style.height = 'auto' - target.style.height = `${Math.min(target.scrollHeight, MAX_HEIGHT)}px` - }, []) - - return ( -
-

- What should we get done? -

- -
-
textareaRef.current?.focus()} - > -