Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
5d7f7e9
improvement(pi): minor improvements to docs (#5192)
icecrasher321 Jun 24, 2026
b212a5d
improvement(mistral): update OCR pricing to OCR 4 rate ($4/1,000 page…
waleedlatif1 Jun 24, 2026
86dc04d
perf(workspace): server-prefetch home, knowledge, tables, and files l…
waleedlatif1 Jun 24, 2026
b52fcc0
refactor(stores): model execution and workflow-diff state as status e…
waleedlatif1 Jun 24, 2026
038e8f0
refactor(sse): consolidate client SSE readers behind a single typed p…
waleedlatif1 Jun 24, 2026
067f9e9
feat(gitlab): support self-managed GitLab host across tools, block, t…
waleedlatif1 Jun 24, 2026
e1c3c7f
feat(secrets): ingest env secrets at container runtime instead of fan…
TheodoreSpeaks Jun 24, 2026
5a938e5
improvement(sandbox): mount workspace files by presigned URL instead …
TheodoreSpeaks Jun 24, 2026
c3a0969
fix(tables): SSR crash from tableKeys in a 'use client' module + drop…
waleedlatif1 Jun 25, 2026
ae4bc05
feat(gitlab): add repository, code-review, and CI job tools + validat…
waleedlatif1 Jun 25, 2026
cff7a49
feat(file): workspace-scoped inline images + public-share cascade (#5…
TheodoreSpeaks Jun 25, 2026
6260eda
fix(ssr): harden credential query-key factory + fetchers against the …
waleedlatif1 Jun 25, 2026
9bd8f14
fix(workspace): add granular error boundaries to 7 more workspace seg…
waleedlatif1 Jun 25, 2026
e748a64
refactor(realtime): type the socket event-handler boundary with @sim/…
waleedlatif1 Jun 25, 2026
34d32b9
feat(salesforce): add Tooling API schema tools (custom field/object) …
waleedlatif1 Jun 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .claude/rules/sim-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ packages/ # @sim/* — audit, auth, db, logger, realtime-protocol
- `apps/* → packages/*` only. Packages never import from `apps/*`.
- `apps/realtime` avoids Next.js, React, the block/tool registry, provider SDKs, and the executor; never add `@/lib/webhooks/providers/*`, `@/executor/*`, `@/blocks/*`, or `@/tools/*` imports to any package it consumes. CI enforces this via `scripts/check-monorepo-boundaries.ts` and `scripts/check-realtime-prune-graph.ts`.

## The `'use client'` server boundary

Every export of a `'use client'` module becomes a *client reference* on the server — server-evaluated code (RSC pages/layouts, `prefetch.ts`, route handlers, block definitions, triggers) can only *render* it as a component or pass it as a prop, never *call* it (doing so throws at runtime, e.g. `tableKeys.list is not a function`; `next build` does not catch it). Keep server-importable query primitives (key factories, fetchers, mappers, constants) in non-`'use client'` modules — see `.claude/rules/sim-queries.md`. Enforced by `scripts/check-client-boundary-imports.ts`.

## Feature Organization

Features live under `app/workspace/[workspaceId]/`:
Expand Down
11 changes: 11 additions & 0 deletions .claude/rules/sim-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ Never use inline query keys — always use the factory.

**Every identifier the `queryFn` forwards into the fetch MUST appear in the `queryKey`.** (Query-machinery identifiers — `signal`, `pageParam` — are exempt; they aren't fetch-scoping args.) If the fetch is scoped by `workspaceId`, `cursor`, `limit`, an org id, etc., those values must be part of the key — otherwise distinct fetch args share one cache entry (a cross-tenant / per-param cache collision). The lone exception is a globally-unique id used as the key while a second fetch arg is only an authz scope that cannot collide; annotate those with `// rq-lint-allow: <reason>`. Enforced by the `key-fetch-arg-drift` check in `scripts/check-react-query-patterns.ts`.

## Server-importable query primitives must NOT live in a `'use client'` module

Next.js rewrites **every** export of a `'use client'` module into a *client reference* in the server bundle. Server-evaluated code — RSC `page.tsx`/`layout.tsx`, `prefetch.ts`, route handlers, **block definitions**, triggers/workers — can only *render* such an export as a component or pass it as a prop; **calling** one throws at runtime (`Attempted to call X from the server but X is on the client` — for an object export it surfaces as `X.list is not a function`). `next build` does **not** catch this — only SSR/runtime does.

So any **query-key factory, standalone `requestJson` fetcher, mapper, or constant** that a server module imports must live in a **non-`'use client'`** module:

- key factories → `hooks/queries/utils/<entity>-keys.ts` (see `folder-keys.ts`, `table-keys.ts`, `credential-keys.ts`)
- standalone fetchers/mappers → `hooks/queries/utils/fetch-*.ts` / `*-list-query.ts` (see `fetch-workflow-envelope.ts`, `fetch-credential-set.ts`)

The `'use client'` hook module then imports these back for its hooks. **Never** define a server-imported factory/fetcher directly in a `'use client'` hooks file — it crashes SSR (this caused the tables-page crash). Enforced for prefetch/route/trigger/block files by `scripts/check-client-boundary-imports.ts` (`bun run check:client-boundary`, run in CI). Escape hatch for a genuinely browser-only path: `// client-boundary-allow: <reason>` on the line above the import.

## File Structure

```typescript
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ jobs:
- name: React Query pattern audit
run: bun run check:react-query

- name: Client boundary import audit
run: bun run check:client-boundary

- name: Verify realtime prune graph
run: bun run check:realtime-prune

Expand Down
464 changes: 464 additions & 0 deletions apps/docs/content/docs/en/integrations/gitlab.mdx

Large diffs are not rendered by default.

150 changes: 147 additions & 3 deletions apps/docs/content/docs/en/integrations/salesforce.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The Salesforce tool is ideal for workflows where your agents need to streamline

## Usage Instructions

Integrate Salesforce into your workflow. Manage accounts, contacts, leads, opportunities, cases, and tasks with powerful automation capabilities.
Integrate Salesforce into your workflow. Manage accounts, contacts, leads, opportunities, cases, and tasks, run reports and SOQL queries, and manage org schema by creating custom fields and objects via the Tooling API.



Expand Down Expand Up @@ -717,7 +717,7 @@ Delete a task

### `salesforce_list_reports`

Get a list of reports accessible by the current user
Get a list of up to 200 recently viewed reports for the current user

#### Input

Expand Down Expand Up @@ -814,7 +814,7 @@ Get a list of available report types

### `salesforce_list_dashboards`

Get a list of dashboards accessible by the current user
Get a list of recently used dashboards for the current user

#### Input

Expand Down Expand Up @@ -1029,6 +1029,150 @@ Get a list of all available Salesforce objects
| ↳ `totalReturned` | number | Number of objects returned |
| ↳ `success` | boolean | Salesforce operation success |

### `salesforce_create_custom_field`

Create a custom field on a Salesforce object (e.g., Account) using the Tooling API

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `idToken` | string | No | No description |
| `instanceUrl` | string | No | No description |
| `objectName` | string | Yes | API name of the object to add the field to \(e.g., Account, Contact, Lead, MyObject__c\) |
| `fieldName` | string | Yes | API name of the new field; the __c suffix is added automatically \(e.g., Region\) |
| `label` | string | No | Display label shown in the UI \(defaults to the field name when omitted\) |
| `fieldType` | string | Yes | Field data type: Text, TextArea, LongTextArea, Html, Number, Currency, Percent, Checkbox, Date, DateTime, Time, Phone, Email, Url, Picklist, or MultiselectPicklist |
| `length` | number | No | Maximum length for Text \(1-255\), LongTextArea, Html, or MultiselectPicklist fields |
| `precision` | number | No | Total number of digits for Number, Currency, or Percent fields \(1-18\) |
| `scale` | number | No | Number of digits to the right of the decimal for numeric fields |
| `visibleLines` | number | No | Number of visible lines for LongTextArea, Html, or MultiselectPicklist fields |
| `required` | boolean | No | Whether the field is required on record create/edit |
| `unique` | boolean | No | Whether the field enforces unique values |
| `externalId` | boolean | No | Whether the field is an external ID \(for Text, Number, or Email fields\) |
| `defaultValue` | string | No | Default value; for Checkbox fields use true or false |
| `description` | string | No | Internal description of the field |
| `inlineHelpText` | string | No | Help text shown next to the field in the UI |
| `picklistValues` | string | No | Comma-separated values for Picklist or MultiselectPicklist fields |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Created custom field metadata |
| ↳ `id` | string | Tooling API Id of the newly created custom field |
| ↳ `fullName` | string | Full API name of the field, including object \(e.g., Account.Region__c\) |
| ↳ `success` | boolean | Whether the create operation was successful |
| ↳ `created` | boolean | Whether the field was created \(always true on success\) |

### `salesforce_update_custom_field`

Update an existing custom field on a Salesforce object using the Tooling API

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `idToken` | string | No | No description |
| `instanceUrl` | string | No | No description |
| `fieldId` | string | Yes | Tooling API Id of the custom field to update \(find it via the Tooling Query tool\) |
| `label` | string | No | Display label shown in the UI |
| `length` | number | No | Maximum length for Text, LongTextArea, Html, or MultiselectPicklist fields |
| `precision` | number | No | Total number of digits for Number, Currency, or Percent fields |
| `scale` | number | No | Number of digits to the right of the decimal for numeric fields |
| `visibleLines` | number | No | Number of visible lines for LongTextArea, Html, or MultiselectPicklist fields |
| `required` | boolean | No | Whether the field is required on record create/edit |
| `unique` | boolean | No | Whether the field enforces unique values |
| `externalId` | boolean | No | Whether the field is an external ID |
| `defaultValue` | string | No | Default value; for Checkbox fields use true or false |
| `description` | string | No | Internal description of the field |
| `inlineHelpText` | string | No | Help text shown next to the field in the UI |
| `picklistValues` | string | No | Comma-separated values to add to a Picklist or MultiselectPicklist field \(existing values are kept\) |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Updated custom field metadata |
| ↳ `id` | string | Tooling API Id of the updated custom field |
| ↳ `updated` | boolean | Whether the field was updated \(always true on success\) |

### `salesforce_delete_custom_field`

Delete a custom field from a Salesforce object using the Tooling API

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `idToken` | string | No | No description |
| `instanceUrl` | string | No | No description |
| `fieldId` | string | Yes | Tooling API Id of the custom field to delete \(find it via the Tooling Query tool\) |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Deleted custom field metadata |
| ↳ `id` | string | Tooling API Id of the deleted custom field |
| ↳ `deleted` | boolean | Whether the field was deleted \(always true on success\) |

### `salesforce_create_custom_object`

Create a custom object in Salesforce using the Tooling API

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `idToken` | string | No | No description |
| `instanceUrl` | string | No | No description |
| `objectName` | string | Yes | API name of the new object; the __c suffix is added automatically \(e.g., Project\) |
| `label` | string | Yes | Singular display label for the object \(e.g., Project\) |
| `pluralLabel` | string | Yes | Plural display label for the object \(e.g., Projects\) |
| `nameFieldLabel` | string | No | Label for the standard Name field \(defaults to "&lt;label&gt; Name"\) |
| `description` | string | No | Internal description of the object |
| `sharingModel` | string | No | Org-wide sharing model: ReadWrite, Read, Private, or ControlledByParent \(default ReadWrite\) |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Created custom object metadata |
| ↳ `id` | string | Tooling API Id of the newly created custom object |
| ↳ `fullName` | string | Full API name of the object \(e.g., Project__c\) |
| ↳ `success` | boolean | Whether the create operation was successful |
| ↳ `created` | boolean | Whether the object was created \(always true on success\) |

### `salesforce_tooling_query`

Execute a SOQL query against the Tooling API to inspect metadata objects

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `idToken` | string | No | No description |
| `instanceUrl` | string | No | No description |
| `query` | string | Yes | Tooling SOQL query \(e.g., SELECT Id, DeveloperName FROM CustomField WHERE TableEnumOrId = 'Account'\) |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Tooling query results |
| ↳ `records` | array | Array of Tooling API records matching the query |
| ↳ `query` | string | The executed Tooling SOQL query |
| ↳ `metadata` | object | Response metadata |
| ↳ `totalReturned` | number | Number of records returned in this response |
| ↳ `hasMore` | boolean | Whether more records exist \(inverse of done\) |
| ↳ `success` | boolean | Salesforce operation success |



## Triggers
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/content/docs/en/workflows/blocks/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"title": "Core Blocks",
"pages": [
"agent",
"pi",
"api",
"function",
"condition",
Expand All @@ -17,6 +16,7 @@
"human-in-the-loop",
"variables",
"wait",
"credential"
"credential",
"pi"
]
}
6 changes: 3 additions & 3 deletions apps/docs/content/docs/en/workflows/blocks/pi.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Pick the mode with the **Mode** dropdown. The fields below it change to match.
Cloud runs entirely inside a disposable sandbox, so it never touches your machine. It clones the repo, lets the agent work with full read/shell/edit/git, pushes a branch, and opens a PR you review and merge.

- Requires sandbox execution to be enabled (the Cloud option only appears when it is).
- Requires **your own provider API key (BYOK)** — the model key is handed to the sandbox, so Sim never injects a hosted key there.
- Requires **your own provider API key (BYOK)** — the model key is handed to the sandbox.
- Needs a **GitHub token** with permission to clone, push, and open a PR (see [Setup](#setup-cloud)).
- The deliverable is a **pull request** — nothing is committed to your default branch directly.

Expand Down Expand Up @@ -118,7 +118,7 @@ The one case neither layer can rescue is a *first* prompt that already exceeds t

## Setup

### Cloud
### Cloud [#setup-cloud]

Cloud runs in a sandbox image with the Pi CLI and git baked in.

Expand All @@ -128,7 +128,7 @@ Cloud runs in a sandbox image with the Pi CLI and git baked in.
- *Fine-grained:* select the repo, then **Contents: Read and write** + **Pull requests: Read and write**.
- *Classic:* the **`repo`** scope. For org repos, authorize the token for SSO.

### Local
### Local [#setup-local]

1. **Enable SSH** on the target machine (on macOS: System Settings → General → Sharing → Remote Login).
2. **Expose it on a public host.** Sim blocks `localhost`/LAN, so use a TCP tunnel — for example `ngrok tcp 22`, which gives a `host:port` to put in **Host** and **Port**.
Expand Down
1 change: 1 addition & 0 deletions apps/realtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@sim/logger": "workspace:*",
"@sim/platform-authz": "workspace:*",
"@sim/realtime-protocol": "workspace:*",
"@sim/runtime-secrets": "workspace:*",
"@sim/security": "workspace:*",
"@sim/utils": "workspace:*",
"@sim/workflow-persistence": "workspace:*",
Expand Down
9 changes: 9 additions & 0 deletions apps/realtime/src/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Container entrypoint. Hydrates `process.env` from the runtime secret before
* loading the Socket.IO server, whose modules (`@/env`, DB preflight) read env
* at import time. See `@sim/runtime-secrets`.
*/
import { loadRuntimeSecrets } from '@sim/runtime-secrets'

await loadRuntimeSecrets()
await import('@/index')
18 changes: 7 additions & 11 deletions apps/sim/app/api/files/export/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { NextResponse } from 'next/server'
import { fileExportContract } from '@/lib/api/contracts/storage-transfer'
import { parseRequest } from '@/lib/api/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { extractEmbeddedImageIds } from '@/lib/copilot/tools/server/files/embedded-image-refs'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import type { StorageContext } from '@/lib/uploads/config'
import { USE_BLOB_STORAGE } from '@/lib/uploads/config'
Expand All @@ -19,9 +20,6 @@ const logger = createLogger('FilesExportAPI')

const MARKDOWN_MIME_TYPES = new Set(['text/markdown', 'text/x-markdown'])
const MARKDOWN_EXTENSIONS = new Set(['md', 'markdown'])
const VIEW_URL_RE =
/\/api\/files\/view\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/gi
const MAX_EMBEDDED_IMAGES = 50

function isMarkdown(originalName: string, contentType: string): boolean {
if (MARKDOWN_MIME_TYPES.has(contentType)) return true
Expand Down Expand Up @@ -82,10 +80,7 @@ export const GET = withRouteHandler(
})
let mdContent = mdBuffer.toString('utf-8')

const imageIds = [...new Set([...mdContent.matchAll(VIEW_URL_RE)].map((m) => m[1]))].slice(
0,
MAX_EMBEDDED_IMAGES
)
const imageIds = extractEmbeddedImageIds(mdContent)

logger.info('Exporting markdown', { id, imageCount: imageIds.length })

Expand Down Expand Up @@ -139,10 +134,11 @@ export const GET = withRouteHandler(
for (const [imageId, asset] of assetMap) {
const escapedId = imageId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
const replacement = `./assets/${asset.filename}`
mdContent = mdContent.replace(
new RegExp(`/api/files/view/${escapedId}`, 'g'),
() => replacement
)
// Rewrite both embed spellings the extractor resolves to this id — the view URL and the in-app
// `/workspace/<ws>/files/<id>` path — so a bundled asset never leaves a broken link in the export.
mdContent = mdContent
.replace(new RegExp(`/api/files/view/${escapedId}`, 'g'), () => replacement)
.replace(new RegExp(`/workspace/[A-Za-z0-9-]+/files/${escapedId}`, 'g'), () => replacement)
}

const zip = new JSZip()
Expand Down
Loading
Loading