chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
# Copilot/Mothership chat streaming entrypoints and replay surfaces.
/apps/sim/app/api/copilot/chat/ @simstudioai/mothership
/apps/sim/app/api/copilot/confirm/ @simstudioai/mothership
/apps/sim/app/api/copilot/chats/ @simstudioai/mothership
/apps/sim/app/api/mothership/chat/ @simstudioai/mothership
/apps/sim/app/api/mothership/chats/ @simstudioai/mothership
/apps/sim/app/api/mothership/execute/ @simstudioai/mothership
/apps/sim/app/api/v1/copilot/chat/ @simstudioai/mothership
# Server-side stream orchestration, persistence, and protocol.
/apps/sim/lib/copilot/chat/ @simstudioai/mothership
/apps/sim/lib/copilot/async-runs/ @simstudioai/mothership
/apps/sim/lib/copilot/request/ @simstudioai/mothership
/apps/sim/lib/copilot/generated/ @simstudioai/mothership
/apps/sim/lib/copilot/constants.ts @simstudioai/mothership
/apps/sim/lib/core/utils/sse.ts @simstudioai/mothership
# Stream-time tool execution, confirmations, resource persistence, and handlers.
/apps/sim/lib/copilot/tool-executor/ @simstudioai/mothership
/apps/sim/lib/copilot/tools/ @simstudioai/mothership
/apps/sim/lib/copilot/persistence/ @simstudioai/mothership
/apps/sim/lib/copilot/resources/ @simstudioai/mothership
# Client-side stream consumption, hydration, and reconnect.
/apps/sim/app/workspace/*/home/hooks/index.ts @simstudioai/mothership
/apps/sim/app/workspace/*/home/hooks/use-chat.ts @simstudioai/mothership
/apps/sim/app/workspace/*/home/hooks/preview/ @simstudioai/mothership
/apps/sim/app/workspace/*/home/hooks/stream/ @simstudioai/mothership
/apps/sim/hooks/queries/tasks.ts @simstudioai/mothership
# Dependency manifests and package-manager config. Any change here — adding,
# removing, or bumping a dependency, or altering install/security settings —
# requires review to guard against supply-chain risk. (CODEOWNERS gates file
# changes, the closest proxy GitHub offers for "new dependency added".)
package.json @simstudioai/deps
**/package.json @simstudioai/deps
bun.lock @simstudioai/deps
**/bun.lock @simstudioai/deps
bunfig.toml @simstudioai/deps
.npmrc @simstudioai/deps
+115
View File
@@ -0,0 +1,115 @@
# Code of Conduct - Sim
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behaviour that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologising to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behaviour include:
- The use of sexualised language or imagery, and sexual attention or advances
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying and enforcing our standards of
acceptable behaviour and will take appropriate and fair corrective action in
response to any behaviour that they deem inappropriate,
threatening, offensive, or harmful.
Project maintainers have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will
communicate reasons for moderation decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behaviour may be
reported to the community leaders responsible for enforcement at <waleed@sim.ai>.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behaviour deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behaviour was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behaviour. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behaviour.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behaviour, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant](https://contributor-covenant.org/), version
[1.4](https://www.contributor-covenant.org/version/1/4/code-of-conduct/code_of_conduct.md) and
[2.0](https://www.contributor-covenant.org/version/2/0/code_of_conduct/code_of_conduct.md),
and was generated by [contributing.md](https://contributing.md/generator).
+641
View File
@@ -0,0 +1,641 @@
# Contributing to Sim
Thank you for your interest in contributing to Sim! Our goal is to provide developers with a powerful, user-friendly platform for building, testing, and optimizing agentic workflows. We welcome contributions in all forms—from bug fixes and design improvements to brand-new features.
> **Project Overview:**
> Sim is a Turborepo monorepo with two deployable apps and a set of shared packages:
>
> - `apps/sim/` — the main Next.js application (App Router, ReactFlow, Zustand, Shadcn, Tailwind CSS).
> - `apps/realtime/` — a small Bun + Socket.IO server that powers the collaborative canvas. Shares DB and Better Auth secrets with `apps/sim` via `@sim/*` packages.
> - `apps/docs/` — Fumadocs-based documentation site.
> - `packages/` — shared workspace packages (`@sim/db`, `@sim/auth`, `@sim/audit`, `@sim/workflow-types`, `@sim/workflow-persistence`, `@sim/platform-authz`, `@sim/realtime-protocol`, `@sim/security`, `@sim/logger`, `@sim/utils`, `@sim/testing`, `@sim/tsconfig`).
>
> Strict one-way dependency flow: `apps/* → packages/*`. Packages never import from apps. Please ensure your contributions follow this and our best practices for clarity, maintainability, and consistency.
---
## Table of Contents
- [How to Contribute](#how-to-contribute)
- [Reporting Issues](#reporting-issues)
- [Pull Request Process](#pull-request-process)
- [Commit Message Guidelines](#commit-message-guidelines)
- [Local Development Setup](#local-development-setup)
- [Adding New Blocks and Tools](#adding-new-blocks-and-tools)
- [License](#license)
- [Contributor License Agreement (CLA)](#contributor-license-agreement-cla)
---
## How to Contribute
We strive to keep our workflow as simple as possible. To contribute:
1. **Fork the Repository**
Click the **Fork** button on GitHub to create your own copy of the project.
2. **Clone Your Fork**
```bash
git clone https://github.com/<your-username>/sim.git
cd sim
```
3. **Create a Feature Branch**
Create a new branch with a descriptive name:
```bash
git checkout -b feat/your-feature-name
```
Use a clear naming convention to indicate the type of work (e.g., `feat/`, `fix/`, `docs/`).
4. **Make Your Changes**
Ensure your changes are small, focused, and adhere to our coding guidelines.
5. **Commit Your Changes**
Write clear, descriptive commit messages that follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#specification) specification. This allows us to maintain a coherent project history and generate changelogs automatically. For example:
- `feat(api): add new endpoint for user authentication`
- `fix(ui): resolve button alignment issue`
- `docs: update contribution guidelines`
6. **Push Your Branch**
```bash
git push origin feat/your-feature-name
```
7. **Create a Pull Request**
Open a pull request against the `staging` branch on GitHub. Please provide a clear description of the changes and reference any relevant issues (e.g., `fixes #123`).
---
## Reporting Issues
If you discover a bug or have a feature request, please open an issue in our GitHub repository. When opening an issue, ensure you:
- Provide a clear, descriptive title.
- Include as many details as possible (steps to reproduce, screenshots, etc.).
- **Tag Your Issue Appropriately:**
Use the following labels to help us categorize your issue:
- **active:** Actively working on it right now.
- **bug:** Something isn't working.
- **design:** Improvements & changes to design & UX.
- **discussion:** Initiate a discussion or propose an idea.
- **documentation:** Improvements or updates to documentation.
- **feature:** New feature or request.
> **Note:** If you're uncertain which label to use, mention it in your issue description and we'll help categorize it.
---
## Pull Request Process
Before creating a pull request:
- **Ensure Your Branch Is Up-to-Date:**
Rebase your branch onto the latest `staging` branch to prevent merge conflicts.
- **Follow the Guidelines:**
Make sure your changes are well-tested, follow our coding standards, and include relevant documentation if necessary.
- **Reference Issues:**
If your PR addresses an existing issue, include `refs #<issue-number>` or `fixes #<issue-number>` in your PR description.
Our maintainers will review your pull request and provide feedback. We aim to make the review process as smooth and timely as possible.
---
## Commit Message Guidelines
We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#specification) standard. Your commit messages should have the following format:
```
<type>[optional scope]: <description>
```
- **Types** may include:
- `feat` a new feature
- `fix` a bug fix
- `docs` documentation changes
- `style` code style changes (formatting, missing semicolons, etc.)
- `refactor` code changes that neither fix a bug nor add a feature
- `test` adding or correcting tests
- `chore` changes to tooling, build process, etc.
- `high priority` a high priority feature or fix
- `high risk` a high risk feature or fix
- `improvement` an improvement to the codebase
_Examples:_
- `feat[auth]: add social login integration`
- `fix[ui]: correct misaligned button on homepage`
- `docs: update installation instructions`
Using clear and consistent commit messages makes it easier for everyone to understand the project history and aids in automating changelog generation.
---
## Local Development Setup
To set up your local development environment:
### Option 1: Using NPM Package (Simplest)
The easiest way to run Sim locally is using our NPM package:
```bash
npx simstudio
```
After running this command, open [http://localhost:3000/](http://localhost:3000/) in your browser.
#### Options
- `-p, --port <port>`: Specify the port to run Sim on (default: 3000)
- `--no-pull`: Skip pulling the latest Docker images
#### Requirements
- Docker must be installed and running on your machine
### Option 2: Using Docker Compose
```bash
# Clone the repository
git clone https://github.com/<your-username>/sim.git
cd sim
# Start Sim
docker compose -f docker-compose.prod.yml up -d
```
Access the application at [http://localhost:3000/](http://localhost:3000/)
#### Using Local Models
To use local models with Sim:
1. Install Ollama and pull models:
```bash
# Install Ollama (if not already installed)
curl -fsSL https://ollama.ai/install.sh | sh
# Pull a model (e.g., gemma3:4b)
ollama pull gemma3:4b
```
2. Start Sim with local model support:
```bash
# With NVIDIA GPU support
docker compose --profile local-gpu -f docker-compose.ollama.yml up -d
# Without GPU (CPU only)
docker compose --profile local-cpu -f docker-compose.ollama.yml up -d
# If hosting on a server, update the environment variables in the docker-compose.prod.yml file
# to include the server's public IP then start again (OLLAMA_URL to i.e. http://1.1.1.1:11434)
docker compose -f docker-compose.prod.yml up -d
```
### Option 3: Using VS Code / Cursor Dev Containers
Dev Containers provide a consistent and easy-to-use development environment:
1. **Prerequisites:**
- Visual Studio Code or Cursor
- Docker Desktop
- [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension for VS Code
2. **Setup Steps:**
- Clone the repository:
```bash
git clone https://github.com/<your-username>/sim.git
cd sim
```
- Open the project in VS Code/Cursor.
- When prompted, click "Reopen in Container" (or press F1 and select "Remote-Containers: Reopen in Container").
- Wait for the container to build and initialize.
3. **Start Developing:**
- Run `bun run dev:full` in the terminal or use the `sim-start` alias.
- This starts both the main application and the realtime socket server.
- All dependencies and configurations are automatically set up.
- Your changes will be automatically hot-reloaded.
4. **GitHub Codespaces:**
- This setup also works with GitHub Codespaces if you prefer development in the browser.
- Just click "Code" → "Codespaces" → "Create codespace on staging".
### Option 4: Manual Setup
If you prefer not to use Docker or Dev Containers. **All commands run from the repository root unless explicitly noted.**
1. **Clone and Install:**
```bash
git clone https://github.com/<your-username>/sim.git
cd sim
bun install
```
Bun workspaces handle dependency resolution for all apps and packages from the root `bun install`.
2. **Set Up Environment Files:**
We use **per-app `.env` files** (the Turborepo-canonical pattern), not a single root `.env`. Three files are needed for local dev:
```bash
# Main app — large, app-specific (OAuth secrets, LLM keys, Stripe, etc.)
cp apps/sim/.env.example apps/sim/.env
# Realtime server — small, only the values shared with the main app
cp apps/realtime/.env.example apps/realtime/.env
# DB tooling (drizzle-kit, db:migrate)
cp packages/db/.env.example packages/db/.env
```
At minimum, each `.env` needs `DATABASE_URL`. `apps/sim/.env` and `apps/realtime/.env` additionally need matching values for `BETTER_AUTH_URL`, `BETTER_AUTH_SECRET`, `INTERNAL_API_SECRET`, and `NEXT_PUBLIC_APP_URL`. `apps/sim/.env` also needs `ENCRYPTION_KEY` and `API_ENCRYPTION_KEY`. Generate any 32-char secrets with `openssl rand -hex 32`.
The same `BETTER_AUTH_SECRET`, `INTERNAL_API_SECRET`, and `DATABASE_URL` must appear in both `apps/sim/.env` and `apps/realtime/.env` so the two services share auth and DB. After editing `apps/sim/.env`, you can mirror the shared subset into the realtime env in one shot:
```bash
grep -E '^(DATABASE_URL|BETTER_AUTH_URL|BETTER_AUTH_SECRET|INTERNAL_API_SECRET|NEXT_PUBLIC_APP_URL|REDIS_URL)=' apps/sim/.env > apps/realtime/.env
grep -E '^DATABASE_URL=' apps/sim/.env > packages/db/.env
```
3. **Run Database Migrations:**
Migrations live in `packages/db/migrations/`. Run them via the dedicated workspace script:
```bash
cd packages/db && bun run db:migrate && cd ../..
```
For ad-hoc schema iteration during development you can also use `bun run db:push` from `packages/db`, but `db:migrate` is the canonical command for both local and CI/CD setups.
4. **Run the Development Servers:**
```bash
bun run dev:full
```
This launches both apps with coloured prefixes:
- `[App]` — Next.js on `http://localhost:3000`
- `[Realtime]` — Socket.IO on `http://localhost:3002`
Or run them separately:
```bash
bun run dev # Next.js app only
bun run dev:sockets # realtime server only
```
5. **Make Your Changes and Test Locally.**
Before opening a PR, run the same checks CI runs:
```bash
bun run type-check # TypeScript across every workspace
bun run lint:check # Biome lint across every workspace
bun run test # Vitest across every workspace
```
### Email Template Development
When working on email templates, you can preview them using a local email preview server:
1. **Run the Email Preview Server:**
```bash
cd apps/sim && bun run email:dev
```
2. **Access the Preview:**
- Open `http://localhost:3000` in your browser.
- You'll see a list of all email templates.
- Click on any template to view and test it with various parameters.
3. **Templates Location:**
- Email templates live in `apps/sim/components/emails/`.
- Changes hot-reload automatically in the preview.
---
## Adding New Blocks and Tools
Sim is built in a modular fashion where blocks and tools extend the platform's functionality. To maintain consistency and quality, please follow the guidelines below when adding a new block or tool.
> **Use the skill guides for step-by-step recipes.** The repository ships opinionated, end-to-end guides under `.agents/skills/` that cover the exact file layout, conventions, registry wiring, and gotchas for each kind of contribution. Read the relevant SKILL.md before you start writing code:
>
> | Adding… | Read |
> | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
> | A new integration end-to-end (tools + block + icon + optional triggers + all registrations) | [`.agents/skills/add-integration/SKILL.md`](../.agents/skills/add-integration/SKILL.md) |
> | Just a block (or aligning an existing block with its tools) | [`.agents/skills/add-block/SKILL.md`](../.agents/skills/add-block/SKILL.md) |
> | Just tool configs for a service | [`.agents/skills/add-tools/SKILL.md`](../.agents/skills/add-tools/SKILL.md) |
> | A webhook trigger for a service | [`.agents/skills/add-trigger/SKILL.md`](../.agents/skills/add-trigger/SKILL.md) |
> | A knowledge-base connector (sync docs from an external source) | [`.agents/skills/add-connector/SKILL.md`](../.agents/skills/add-connector/SKILL.md) |
>
> The shorter overview below is a high-level reference; the SKILL.md files are the authoritative source of truth and stay in sync with the codebase.
### Where to Add Your Code
- **Blocks:** Create your new block file under the `apps/sim/blocks/blocks/` directory. The name of the file should match the provider name (e.g., `pinecone.ts`).
- **Tools:** Create a new directory under `apps/sim/tools/` with the same name as the provider (e.g., `apps/sim/tools/pinecone`).
In addition, you will need to update the registries:
- **Block Registry:** Add your block to `apps/sim/blocks/registry.ts`. (`apps/sim/blocks/index.ts` re-exports lookups from the registry; you do not need to edit it.)
- **Tool Registry:** Add your tool to `apps/sim/tools/index.ts`.
### How to Create a New Block
1. **Create a New File:**
Create a file for your block named after the provider (e.g., `pinecone.ts`) in the `apps/sim/blocks/blocks/` directory.
2. **Create a New Icon:**
Create a new icon for your block in `apps/sim/components/icons.tsx`. The icon should follow the same naming convention as the block (e.g., `PineconeIcon`).
3. **Define the Block Configuration:**
Your block should export a constant of type `BlockConfig`. For example:
```typescript
// apps/sim/blocks/blocks/pinecone.ts
import { PineconeIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import type { PineconeResponse } from '@/tools/pinecone/types'
export const PineconeBlock: BlockConfig<PineconeResponse> = {
type: 'pinecone',
name: 'Pinecone',
description: 'Use Pinecone vector database',
longDescription: 'A more detailed description of what this block does and how to use it.',
category: 'tools',
bgColor: '#123456',
icon: PineconeIcon,
subBlocks: [
{
id: 'operation',
title: 'Operation',
type: 'dropdown',
required: true,
options: [
{ label: 'Generate Embeddings', id: 'generate' },
{ label: 'Search Text', id: 'search_text' },
],
value: () => 'generate',
},
{
id: 'apiKey',
title: 'API Key',
type: 'short-input',
placeholder: 'Your Pinecone API key',
password: true,
required: true,
},
],
tools: {
access: ['pinecone_generate_embeddings', 'pinecone_search_text'],
config: {
tool: (params: Record<string, any>) => {
switch (params.operation) {
case 'generate':
return 'pinecone_generate_embeddings'
case 'search_text':
return 'pinecone_search_text'
default:
throw new Error('Invalid operation selected')
}
},
},
},
inputs: {
operation: { type: 'string', description: 'Operation to perform' },
apiKey: { type: 'string', description: 'Pinecone API key' },
searchQuery: { type: 'string', description: 'Search query text' },
topK: { type: 'string', description: 'Number of results to return' },
},
outputs: {
matches: { type: 'any', description: 'Search results or generated embeddings' },
data: { type: 'any', description: 'Response data from Pinecone' },
usage: { type: 'any', description: 'API usage statistics' },
},
}
```
4. **Register Your Block:**
Add your block to the blocks registry (`apps/sim/blocks/registry.ts`):
```typescript
// apps/sim/blocks/registry.ts
import { PineconeBlock } from '@/blocks/blocks/pinecone'
// Registry of all available blocks
export const registry: Record<string, BlockConfig> = {
// ... existing blocks
pinecone: PineconeBlock,
}
```
The block will be automatically available to the application through the registry.
5. **Test Your Block:**
Ensure that the block displays correctly in the UI and that its functionality works as expected.
### How to Create a New Tool
1. **Create a New Directory:**
Create a directory under `apps/sim/tools/` with the same name as the provider (e.g., `apps/sim/tools/pinecone`).
2. **Create Tool Files:**
Create separate files for each tool functionality with descriptive names (e.g., `fetch.ts`, `generate_embeddings.ts`, `search_text.ts`) in your tool directory.
3. **Create a Types File:**
Create a `types.ts` file in your tool directory to define and export all types related to your tools.
4. **Create an Index File:**
Create an `index.ts` file in your tool directory that imports and exports all tools:
```typescript
// apps/sim/tools/pinecone/index.ts
import { fetchTool } from './fetch'
import { generateEmbeddingsTool } from './generate_embeddings'
import { searchTextTool } from './search_text'
export { fetchTool, generateEmbeddingsTool, searchTextTool }
```
5. **Define the Tool Configuration:**
Your tool should export a constant with a naming convention of `{toolName}Tool`. The tool ID should follow the format `{provider}_{tool_name}`. For example:
```typescript
// apps/sim/tools/pinecone/fetch.ts
import { ToolConfig, ToolResponse } from '@/tools/types'
import { PineconeParams, PineconeResponse } from '@/tools/pinecone/types'
export const fetchTool: ToolConfig<PineconeParams, PineconeResponse> = {
id: 'pinecone_fetch', // Follow the {provider}_{tool_name} format
name: 'Pinecone Fetch',
description: 'Fetch vectors from Pinecone database',
version: '1.0.0',
// OAuth configuration (if applicable)
provider: 'pinecone', // ID of the OAuth provider
params: {
parameterName: {
type: 'string',
required: true,
visibility: 'user-or-llm', // Controls parameter visibility
description: 'Description of the parameter',
},
optionalParam: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Optional parameter only user can set',
},
},
request: {
// Request configuration
},
transformResponse: async (response: Response) => {
// Transform response
},
}
```
6. **Register Your Tool:**
Update the tools registry in `apps/sim/tools/index.ts` to include your new tool:
```typescript
// apps/sim/tools/index.ts
import { fetchTool, generateEmbeddingsTool, searchTextTool } from '@/tools/pinecone'
// ... other imports
export const tools: Record<string, ToolConfig> = {
// ... existing tools
pinecone_fetch: fetchTool,
pinecone_generate_embeddings: generateEmbeddingsTool,
pinecone_search_text: searchTextTool,
}
```
7. **Test Your Tool:**
Ensure that your tool functions correctly by making test requests and verifying the responses.
8. **Generate Documentation:**
Run the documentation generator (from `apps/sim`) to create docs for your new tool:
```bash
cd apps/sim && bun run generate-docs
```
### Naming Conventions
Maintaining consistent naming across the codebase is critical for auto-generation of tools and documentation. Follow these naming guidelines:
- **Block Files:** Name should match the provider (e.g., `pinecone.ts`)
- **Block Export:** Should be named `{Provider}Block` (e.g., `PineconeBlock`)
- **Icons:** Should be named `{Provider}Icon` (e.g., `PineconeIcon`)
- **Tool Directories:** Should match the provider name (e.g., `tools/pinecone/`)
- **Tool Files:** Should be named after their function (e.g., `fetch.ts`, `search_text.ts`)
- **Tool Exports:** Should be named `{toolName}Tool` (e.g., `fetchTool`)
- **Tool IDs:** Should follow the format `{provider}_{tool_name}` (e.g., `pinecone_fetch`)
### Parameter Visibility System
Sim implements a sophisticated parameter visibility system that controls how parameters are exposed to users and LLMs in agent workflows. Each parameter can have one of four visibility levels:
| Visibility | User Sees | LLM Sees | How It Gets Set |
| ------------- | --------- | -------- | ------------------------------ |
| `user-only` | ✅ Yes | ❌ No | User provides in UI |
| `user-or-llm` | ✅ Yes | ✅ Yes | User provides OR LLM generates |
| `llm-only` | ❌ No | ✅ Yes | LLM generates only |
| `hidden` | ❌ No | ❌ No | Application injects at runtime |
#### Visibility Guidelines
- **`user-or-llm`**: Use for core parameters that can be provided by users or intelligently filled by the LLM (e.g., search queries, email subjects)
- **`user-only`**: Use for configuration parameters, API keys, and settings that only users should control (e.g., number of results, authentication credentials)
- **`llm-only`**: Use for computed values that the LLM should handle internally (e.g., dynamic calculations, contextual data)
- **`hidden`**: Use for system-level parameters injected at runtime (e.g., OAuth tokens, internal identifiers)
#### Example Implementation
```typescript
params: {
query: {
type: 'string',
required: true,
visibility: 'user-or-llm', // User can provide or LLM can generate
description: 'Search query to execute',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only', // Only user provides this
description: 'API key for authentication',
},
internalId: {
type: 'string',
required: false,
visibility: 'hidden', // System provides this at runtime
description: 'Internal tracking identifier',
},
}
```
This visibility system ensures clean user interfaces while maintaining full flexibility for LLM-driven workflows.
### Guidelines & Best Practices
- **Code Style:** Follow the project's Biome configurations. Use meaningful variable names and small, focused functions.
- **Documentation:** Clearly document the purpose, inputs, outputs, and any special behavior for your block/tool.
- **Error Handling:** Implement robust error handling and provide user-friendly error messages.
- **Parameter Visibility:** Always specify the appropriate visibility level for each parameter to ensure proper UI behavior and LLM integration.
- **Testing:** Add unit or integration tests to verify your changes when possible.
- **Commit Changes:** Update all related components and registries, and describe your changes in your pull request.
Happy coding!
---
## License
This project is licensed under the Apache License 2.0. By contributing, you agree that your contributions will be licensed under the Apache License 2.0 as well.
---
## Contributor License Agreement (CLA)
By contributing to this repository, you agree that your contributions are provided under the terms of the Apache License Version 2.0, as included in the LICENSE file of this repository.
In addition, by submitting your contributions, you grant Sim, Inc. ("The Licensor") a perpetual, irrevocable, worldwide, royalty-free, sublicensable right and license to:
- Use, copy, modify, distribute, publicly display, publicly perform, and prepare derivative works of your contributions.
- Incorporate your contributions into other works or products.
- Re-license your contributions under a different license at any time in the future, at the Licensor's sole discretion.
You represent and warrant that you have the legal authority to grant these rights and that your contributions are original or you have sufficient rights to submit them under these terms.
If you do not agree with these terms, you must not contribute your work to this repository.
---
Thank you for taking the time to contribute to Sim. We truly appreciate your efforts and look forward to collaborating with you!
+27
View File
@@ -0,0 +1,27 @@
---
name: Bug report
about: Create a report to help us improve
title: '[BUG]'
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
+19
View File
@@ -0,0 +1,19 @@
---
name: Feature request
about: Suggest an idea for this project
title: '[REQUEST]'
labels: feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+25
View File
@@ -0,0 +1,25 @@
## Summary
Brief description of what this PR does and why.
Fixes #(issue)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation
- [ ] Other: ___________
## Testing
How has this been tested? What should reviewers focus on?
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-reviewed my changes
- [ ] Tests added/updated and passing
- [ ] No new warnings introduced
- [ ] I confirm that I have read and agree to the terms outlined in the [Contributor License Agreement (CLA)](./CONTRIBUTING.md#contributor-license-agreement-cla)
## Screenshots/Videos
<!-- If applicable, add screenshots or videos to help explain your changes -->
<!-- For UI changes, before/after screenshots are especially helpful -->
+26
View File
@@ -0,0 +1,26 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 0.1.x | :white_check_mark: |
## Reporting a Vulnerability
We take the security of Sim seriously. If you believe you've found a security vulnerability, please follow these steps:
1. **Do not disclose the vulnerability publicly** or to any third parties.
2. **Email us directly** at security@sim.ai with details of the vulnerability.
3. **Include the following information** in your report:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Any suggestions for mitigation
4. We will acknowledge receipt of your vulnerability report within 48 hours and provide an estimated timeline for a fix.
5. Once the vulnerability is fixed, we will notify you and publicly acknowledge your contribution (unless you prefer to remain anonymous).
+448
View File
@@ -0,0 +1,448 @@
name: CI
on:
push:
branches: [main, staging, dev]
pull_request:
branches: [main, staging, dev]
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
jobs:
test-build:
name: Test and Build
if: github.ref != 'refs/heads/dev' || github.event_name == 'pull_request'
uses: ./.github/workflows/test-build.yml
secrets: inherit
# Detect if this is a version release commit (e.g., "v0.5.24: ...")
detect-version:
name: Detect Version
runs-on: blacksmith-4vcpu-ubuntu-2404
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging' || github.ref == 'refs/heads/dev')
outputs:
version: ${{ steps.extract.outputs.version }}
is_release: ${{ steps.extract.outputs.is_release }}
steps:
- name: Extract version from commit message
id: extract
env:
COMMIT_MSG: ${{ github.event.head_commit.message }}
run: |
# Only tag versions on main branch
if [ "$GITHUB_REF" = "refs/heads/main" ] && [[ "$COMMIT_MSG" =~ ^(v[0-9]+\.[0-9]+\.[0-9]+): ]]; then
VERSION="${BASH_REMATCH[1]}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "is_release=true" >> $GITHUB_OUTPUT
echo "✅ Detected release commit: ${VERSION}"
else
echo "version=" >> $GITHUB_OUTPUT
echo "is_release=false" >> $GITHUB_OUTPUT
echo "️ Not a release commit"
fi
# Run database migrations before images are pushed: the ECR push triggers
# CodePipeline, so migrating first guarantees the schema is in place before
# the new app version deploys (replaces the removed ECS migration sidecar)
migrate:
name: Migrate DB
needs: [test-build]
if: >-
github.event_name == 'push' &&
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
uses: ./.github/workflows/migrations.yml
with:
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
secrets: inherit
# Same ordering for dev (schema push before the dev image lands in ECR)
migrate-dev:
name: Migrate Dev DB
if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
uses: ./.github/workflows/migrations.yml
with:
environment: dev
secrets: inherit
# Dev: build all 3 images for ECR only (no GHCR, no ARM64)
build-dev:
name: Build Dev ECR
needs: [detect-version, migrate-dev]
if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
runs-on: blacksmith-8vcpu-ubuntu-2404
permissions:
contents: read
id-token: write
strategy:
fail-fast: false
matrix:
include:
- dockerfile: ./docker/app.Dockerfile
ecr_repo_secret: ECR_APP
- dockerfile: ./docker/db.Dockerfile
ecr_repo_secret: ECR_MIGRATIONS
- dockerfile: ./docker/realtime.Dockerfile
ecr_repo_secret: ECR_REALTIME
- dockerfile: ./docker/pii.Dockerfile
ecr_repo_secret: ECR_PII
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6
with:
role-to-assume: ${{ secrets.DEV_AWS_ROLE_TO_ASSUME }}
aws-region: ${{ secrets.DEV_AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@d539f0932e70871a027e9d5a9d8fc38589180a64 # v2
- name: Login to Docker Hub
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1
- name: Resolve ECR repo name
id: ecr-repo
run: echo "name=$ECR_REPO" >> $GITHUB_OUTPUT
env:
ECR_REPO: ${{ matrix.ecr_repo_secret == 'ECR_APP' && secrets.ECR_APP || matrix.ecr_repo_secret == 'ECR_MIGRATIONS' && secrets.ECR_MIGRATIONS || matrix.ecr_repo_secret == 'ECR_REALTIME' && secrets.ECR_REALTIME || matrix.ecr_repo_secret == 'ECR_PII' && secrets.ECR_PII || '' }}
- name: Build and push
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64
push: true
tags: ${{ steps.login-ecr.outputs.registry }}/${{ steps.ecr-repo.outputs.name }}:dev
provenance: false
sbom: false
# Dev: deploy Trigger.dev background tasks to the preview "dev-sim" branch.
# Gated after migrate-dev for the same reason as build-dev — the new task
# code runs against the dev DB, so the schema must be pushed first.
deploy-trigger-dev:
name: Deploy Trigger.dev (Dev)
needs: [migrate-dev]
if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.13
- name: Cache Bun dependencies
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
~/.bun/install/cache
node_modules
**/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Deploy to Trigger.dev
working-directory: ./apps/sim
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.DEV_TRIGGER_ACCESS_TOKEN }}
TRIGGER_PROJECT_ID: ${{ secrets.TRIGGER_PROJECT_ID }}
run: |
if [ -z "$TRIGGER_ACCESS_TOKEN" ] || [ -z "$TRIGGER_PROJECT_ID" ]; then
echo "ERROR: DEV_TRIGGER_ACCESS_TOKEN and TRIGGER_PROJECT_ID repo secrets must both be set" >&2
exit 1
fi
bunx trigger.dev@4.4.3 deploy --env preview --branch dev-sim
# Main/staging: build AMD64 images and push to ECR + GHCR
build-amd64:
name: Build AMD64
needs: [test-build, detect-version, migrate]
if: >-
github.event_name == 'push' &&
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
runs-on: blacksmith-8vcpu-ubuntu-2404
permissions:
contents: read
packages: write
id-token: write
strategy:
fail-fast: false
matrix:
include:
- dockerfile: ./docker/app.Dockerfile
ghcr_image: ghcr.io/simstudioai/simstudio
ecr_repo_secret: ECR_APP
- dockerfile: ./docker/db.Dockerfile
ghcr_image: ghcr.io/simstudioai/migrations
ecr_repo_secret: ECR_MIGRATIONS
- dockerfile: ./docker/realtime.Dockerfile
ghcr_image: ghcr.io/simstudioai/realtime
ecr_repo_secret: ECR_REALTIME
- dockerfile: ./docker/pii.Dockerfile
ghcr_image: ghcr.io/simstudioai/pii
ecr_repo_secret: ECR_PII
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6
with:
role-to-assume: ${{ github.ref == 'refs/heads/main' && secrets.AWS_ROLE_TO_ASSUME || secrets.STAGING_AWS_ROLE_TO_ASSUME }}
aws-region: ${{ github.ref == 'refs/heads/main' && secrets.AWS_REGION || secrets.STAGING_AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@d539f0932e70871a027e9d5a9d8fc38589180a64 # v2
- name: Login to Docker Hub
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR
if: github.ref == 'refs/heads/main'
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1
- name: Resolve ECR repo name
id: ecr-repo
run: echo "name=$ECR_REPO" >> $GITHUB_OUTPUT
env:
ECR_REPO: ${{ matrix.ecr_repo_secret == 'ECR_APP' && secrets.ECR_APP || matrix.ecr_repo_secret == 'ECR_MIGRATIONS' && secrets.ECR_MIGRATIONS || matrix.ecr_repo_secret == 'ECR_REALTIME' && secrets.ECR_REALTIME || matrix.ecr_repo_secret == 'ECR_PII' && secrets.ECR_PII || '' }}
- name: Generate tags
id: meta
run: |
ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}"
ECR_REPO="${{ steps.ecr-repo.outputs.name }}"
GHCR_IMAGE="${{ matrix.ghcr_image }}"
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
ECR_TAG="latest"
else
ECR_TAG="staging"
fi
ECR_IMAGE="${ECR_REGISTRY}/${ECR_REPO}:${ECR_TAG}"
TAGS="${ECR_IMAGE}"
if [ "${{ github.ref }}" = "refs/heads/main" ] && [ -n "$GHCR_IMAGE" ]; then
GHCR_AMD64="${GHCR_IMAGE}:latest-amd64"
GHCR_SHA="${GHCR_IMAGE}:${{ github.sha }}-amd64"
TAGS="${TAGS},$GHCR_AMD64,$GHCR_SHA"
if [ "${{ needs.detect-version.outputs.is_release }}" = "true" ]; then
VERSION="${{ needs.detect-version.outputs.version }}"
GHCR_VERSION="${GHCR_IMAGE}:${VERSION}-amd64"
TAGS="${TAGS},$GHCR_VERSION"
echo "📦 Adding version tag: ${VERSION}-amd64"
fi
fi
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
- name: Build and push images
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
provenance: false
sbom: false
# Build ARM64 images for GHCR (main branch only, runs in parallel)
build-ghcr-arm64:
name: Build ARM64 (GHCR Only)
needs: [detect-version]
runs-on: blacksmith-8vcpu-ubuntu-2404-arm
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- dockerfile: ./docker/app.Dockerfile
image: ghcr.io/simstudioai/simstudio
- dockerfile: ./docker/db.Dockerfile
image: ghcr.io/simstudioai/migrations
- dockerfile: ./docker/realtime.Dockerfile
image: ghcr.io/simstudioai/realtime
- dockerfile: ./docker/pii.Dockerfile
image: ghcr.io/simstudioai/pii
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Login to GHCR
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: useblacksmith/setup-docker-builder@ab5c1da94f53f5cd75c1038092aa276dddfccbba # v1
- name: Generate ARM64 tags
id: meta
run: |
IMAGE="${{ matrix.image }}"
TAGS="${IMAGE}:latest-arm64,${IMAGE}:${{ github.sha }}-arm64"
# Add version tag if this is a release commit
if [ "${{ needs.detect-version.outputs.is_release }}" = "true" ]; then
VERSION="${{ needs.detect-version.outputs.version }}"
TAGS="${TAGS},${IMAGE}:${VERSION}-arm64"
echo "📦 Adding version tag: ${VERSION}-arm64"
fi
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
- name: Build and push ARM64 to GHCR
uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
provenance: false
sbom: false
# Create GHCR multi-arch manifests (only for main, after both builds)
create-ghcr-manifests:
name: Create GHCR Manifests
runs-on: blacksmith-2vcpu-ubuntu-2404
needs: [build-amd64, build-ghcr-arm64, detect-version]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
packages: write
strategy:
matrix:
include:
- image: ghcr.io/simstudioai/simstudio
- image: ghcr.io/simstudioai/migrations
- image: ghcr.io/simstudioai/realtime
- image: ghcr.io/simstudioai/pii
steps:
- name: Login to GHCR
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push manifests
run: |
IMAGE_BASE="${{ matrix.image }}"
# Create latest manifest
docker manifest create "${IMAGE_BASE}:latest" \
"${IMAGE_BASE}:latest-amd64" \
"${IMAGE_BASE}:latest-arm64"
docker manifest push "${IMAGE_BASE}:latest"
# Create SHA manifest
docker manifest create "${IMAGE_BASE}:${{ github.sha }}" \
"${IMAGE_BASE}:${{ github.sha }}-amd64" \
"${IMAGE_BASE}:${{ github.sha }}-arm64"
docker manifest push "${IMAGE_BASE}:${{ github.sha }}"
# Create version manifest if this is a release commit
if [ "${{ needs.detect-version.outputs.is_release }}" = "true" ]; then
VERSION="${{ needs.detect-version.outputs.version }}"
echo "📦 Creating version manifest: ${VERSION}"
docker manifest create "${IMAGE_BASE}:${VERSION}" \
"${IMAGE_BASE}:${VERSION}-amd64" \
"${IMAGE_BASE}:${VERSION}-arm64"
docker manifest push "${IMAGE_BASE}:${VERSION}"
fi
# Check if docs changed
check-docs-changes:
name: Check Docs Changes
runs-on: blacksmith-4vcpu-ubuntu-2404
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
outputs:
docs_changed: ${{ steps.filter.outputs.docs }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 2 # Need at least 2 commits to detect changes
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
id: filter
with:
filters: |
docs:
- 'apps/docs/content/docs/en/**'
- 'apps/sim/scripts/process-docs.ts'
- 'apps/sim/lib/chunkers/**'
# Process docs embeddings (only when docs change, after ECR images are pushed)
process-docs:
name: Process Docs
needs: [build-amd64, check-docs-changes]
if: needs.check-docs-changes.outputs.docs_changed == 'true'
uses: ./.github/workflows/docs-embeddings.yml
secrets: inherit
# Create GitHub Release (only for version commits on main, after all builds complete)
create-release:
name: Create GitHub Release
runs-on: blacksmith-4vcpu-ubuntu-2404
needs: [create-ghcr-manifests, detect-version]
if: needs.detect-version.outputs.is_release == 'true'
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.13
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Create release
env:
GH_PAT: ${{ secrets.GITHUB_TOKEN }}
run: bun run scripts/create-single-release.ts ${{ needs.detect-version.outputs.version }}
+207
View File
@@ -0,0 +1,207 @@
name: companion-pr-check
# Soft, NON-BLOCKING warning: when a PR targeting staging/main declares a
# cross-repo "Companion:" PR, surface whether that companion is merged yet, so
# copilot and sim stay in lockstep (a change in one often needs the other).
#
# Declare in a PR description (repeatable; shorthand OR full URL both parse):
# Companion: simstudioai/sim#1234
# Companion: https://github.com/simstudioai/sim/pull/1234
#
# Requires a CROSS_REPO_TOKEN secret (fine-grained PAT with pull-requests:read on
# BOTH repos) to read the other repo's PR state. Without it the check still
# surfaces the declared link but reports "couldn't verify".
on:
# PR-driven only: runs on the one PR being opened/edited/synced — no periodic
# bulk scan. We assume companions are declared on BOTH sides, so the per-PR
# trigger keeps each side's status fresh; to refresh after a companion merges,
# re-edit the PR (or run this workflow manually via the Actions tab).
pull_request:
types: [opened, edited, reopened, synchronize]
branches: [staging, main]
workflow_dispatch: {}
permissions:
pull-requests: write
issues: write
contents: read
jobs:
companion:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
env:
CROSS_REPO_TOKEN: ${{ secrets.CROSS_REPO_TOKEN }}
with:
script: |
const STICKY = '<!-- companion-pr-check -->';
const { owner, repo } = context.repo;
// Directional label: copilot/mothership PRs get "requires-sim-merge",
// sim PRs get "requires-mothership-merge". Applied whenever the PR
// declares a companion; removed when it declares none.
const otherSide = repo === 'sim' ? 'mothership/copilot' : 'sim';
const LABEL = repo === 'sim' ? 'requires-mothership-merge' : 'requires-sim-merge';
const LABEL_DESC = `Has a companion PR on the ${otherSide} side — merge in lockstep`;
const crossToken = process.env.CROSS_REPO_TOKEN;
// Read the OTHER repo's PR via a plain REST fetch with the PAT in the
// header — keeps the PAT strictly READ-ONLY and avoids re-instantiating
// Octokit inside github-script (which can't require('@actions/github')).
// Commenting/labeling uses the default GITHUB_TOKEN via `github`.
async function crossGetPR(c) {
const res = await fetch(`https://api.github.com/repos/${c.owner}/${c.repo}/pulls/${c.number}`, {
headers: {
authorization: `Bearer ${crossToken}`,
accept: 'application/vnd.github+json',
'x-github-api-version': '2022-11-28',
'user-agent': 'companion-pr-check',
},
});
if (!res.ok) { const e = new Error(`HTTP ${res.status}`); e.status = res.status; throw e; }
return res.json();
}
// Two ways to declare a companion (either works; both feed this warning):
// 1) a trailer anywhere: Companion: owner/repo#N (or a full PR URL)
// 2) refs in a task list under a "## Companion..." heading — which ALSO
// renders a native live badge + progress bar on the PR (the "both" path):
// ## Companion PRs
// - [ ] owner/repo#N
// Regexes are local + matchAll, so there's no shared lastIndex state to leak
// between calls (stateless by construction).
function parseCompanions(body) {
body = body || '';
const TRAILER = /Companion:\s*(?:https?:\/\/github\.com\/)?([\w.-]+)\/([\w.-]+)(?:\/pull\/|#)(\d+)/gi;
const REF = /(?:https?:\/\/github\.com\/)?([\w.-]+)\/([\w.-]+)(?:\/pull\/|#)(\d+)/g;
const out = [];
const seen = new Set();
const add = (o, r, n) => {
const ref = `${o}/${r}#${n}`;
if (seen.has(ref)) return;
seen.add(ref);
out.push({ owner: o, repo: r, number: Number(n), ref });
};
// (1) "Companion:" trailers anywhere in the body.
for (const m of body.matchAll(TRAILER)) add(m[1], m[2], m[3]);
// (2) refs in a task list under a "## Companion..." heading, until the next heading.
let inSection = false;
for (const line of body.split(/\r?\n/)) {
if (/^#{1,6}\s/.test(line)) { inSection = /^#{1,6}\s*companion/i.test(line); continue; }
if (!inSection) continue;
for (const mm of line.matchAll(REF)) add(mm[1], mm[2], mm[3]);
}
return out;
}
async function findSticky(prNumber) {
const comments = await github.paginate(github.rest.issues.listComments, {
owner, repo, issue_number: prNumber, per_page: 100,
});
return comments.find((c) => (c.body || '').includes(STICKY));
}
async function upsert(prNumber, body) {
const ex = await findSticky(prNumber);
if (ex) await github.rest.issues.updateComment({ owner, repo, comment_id: ex.id, body });
else await github.rest.issues.createComment({ owner, repo, issue_number: prNumber, body });
}
async function clear(prNumber) {
const ex = await findSticky(prNumber);
if (ex) await github.rest.issues.deleteComment({ owner, repo, comment_id: ex.id });
// Drop the label too, so a PR edited to remove all companions doesn't
// keep a stale badge. 404 (not present) is expected; surface anything else.
try { await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name: LABEL }); }
catch (e) { if (e.status !== 404) core.warning(`companion: removeLabel ${LABEL} on #${prNumber} failed (${e.status || e.message})`); }
}
async function ensureLabel() {
try { await github.rest.issues.getLabel({ owner, repo, name: LABEL }); return; }
catch (e) { if (e.status && e.status !== 404) { core.warning(`companion: getLabel ${LABEL} failed (${e.status})`); return; } }
// 404 → label doesn't exist yet, create it. 422 = another run beat us (fine).
try { await github.rest.issues.createLabel({ owner, repo, name: LABEL, color: 'd93f0b', description: LABEL_DESC }); }
catch (e) { if (e.status !== 422) core.warning(`companion: createLabel ${LABEL} failed (${e.status || e.message})`); }
}
// staging PRs are a single feature → just this PR's body ("the one").
// main (prod) release PRs bundle MANY feature PRs → aggregate the
// companions declared on each squashed feature PR too, so "does any
// commit in this release have a companion?" is answered.
async function collectCompanions(pr) {
const companions = parseCompanions(pr.body);
const seen = new Set(companions.map((c) => c.ref));
if (pr.base.ref === 'main') {
let commits = [];
try {
commits = await github.paginate(github.rest.pulls.listCommits, {
owner, repo, pull_number: pr.number, per_page: 100,
});
} catch {}
const featurePRs = new Set();
const SQUASH = /\(#(\d+)\)/g; // squash-merge refs like "...(#306)"
for (const c of commits) {
const msg = (c.commit && c.commit.message) || '';
let m;
SQUASH.lastIndex = 0;
while ((m = SQUASH.exec(msg)) !== null) featurePRs.add(Number(m[1]));
}
for (const n of featurePRs) {
if (n === pr.number) continue;
try {
const { data: fpr } = await github.rest.pulls.get({ owner, repo, pull_number: n });
for (const c of parseCompanions(fpr.body)) {
if (!seen.has(c.ref)) { seen.add(c.ref); companions.push(c); }
}
} catch {}
}
}
return companions;
}
async function checkPR(pr) {
const companions = await collectCompanions(pr);
if (companions.length === 0) { await clear(pr.number); return; }
await ensureLabel();
try { await github.rest.issues.addLabels({ owner, repo, issue_number: pr.number, labels: [LABEL] }); }
catch (e) { core.warning(`companion: addLabels ${LABEL} on #${pr.number} failed (${e.status || e.message})`); }
const base = pr.base.ref;
const lines = [];
let warn = false;
for (const c of companions) {
if (!crossToken) {
lines.push(`- ❓ \`${c.ref}\` — set the **CROSS_REPO_TOKEN** secret to verify merge status`);
warn = true;
continue;
}
try {
const cp = await crossGetPR(c);
const title = (cp.title || '').slice(0, 80);
if (cp.merged) {
const tierOk = cp.base.ref === base;
lines.push(`- ${tierOk ? '✅' : '⚠️'} [\`${c.ref}\`](${cp.html_url}) — merged into \`${cp.base.ref}\`${tierOk ? '' : ` (this PR targets \`${base}\`)`} — ${title}`);
if (!tierOk) warn = true;
} else {
lines.push(`- ❌ [\`${c.ref}\`](${cp.html_url}) — **${String(cp.state).toUpperCase()}, not merged** (targets \`${cp.base.ref}\`) — ${title}`);
warn = true;
}
} catch (e) {
lines.push(`- ❓ \`${c.ref}\` — couldn't read (${e.status || e.message}); check CROSS_REPO_TOKEN scope`);
warn = true;
}
}
const heading = warn ? '## ⚠️ Cross-repo companion check' : '## ✅ Cross-repo companion check';
const scope = base === 'main' ? ' (aggregated across the feature PRs in this release)' : '';
const note = warn
? `One or more companion PRs aren't merged into \`${base}\` yet${scope}. Merging this without them will leave copilot and sim out of sync — merge them in lockstep.`
: `All declared companion PRs are merged into \`${base}\`${scope}.`;
await upsert(pr.number, `${STICKY}\n${heading}\n\n${note}\n\n${lines.join('\n')}`);
}
if (context.eventName === 'pull_request') {
await checkPR(context.payload.pull_request);
} else {
// workflow_dispatch only: manual full re-scan of open staging/main PRs.
for (const b of ['staging', 'main']) {
const prs = await github.paginate(github.rest.pulls.list, { owner, repo, base: b, state: 'open', per_page: 100 });
for (const pr of prs) await checkPR(pr);
}
}
+49
View File
@@ -0,0 +1,49 @@
name: Process Docs Embeddings
on:
workflow_call:
workflow_dispatch: # Allow manual triggering
permissions:
contents: read
jobs:
process-docs-embeddings:
name: Process Documentation Embeddings
runs-on: blacksmith-8vcpu-ubuntu-2404
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.13
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: latest
- name: Cache Bun dependencies
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
~/.bun/install/cache
node_modules
**/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Process docs embeddings
working-directory: ./apps/sim
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: bun run scripts/process-docs.ts --clear
+178
View File
@@ -0,0 +1,178 @@
name: 'Auto-translate Documentation'
on:
workflow_dispatch: # Manual trigger only (scheduled runs disabled)
permissions:
contents: write
pull-requests: write
jobs:
translate:
runs-on: blacksmith-4vcpu-ubuntu-2404
if: github.actor != 'github-actions[bot]' # Prevent infinite loops
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
ref: staging
token: ${{ secrets.GH_PAT }}
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.13
- name: Cache Bun dependencies
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
~/.bun/install/cache
node_modules
**/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Run Lingo.dev translations
env:
LINGODOTDEV_API_KEY: ${{ secrets.LINGODOTDEV_API_KEY }}
run: |
cd apps/docs
bunx lingo.dev@latest i18n
- name: Check for translation changes
id: changes
run: |
cd apps/docs
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
if [ -n "$(git status --porcelain content/docs)" ]; then
echo "changes=true" >> $GITHUB_OUTPUT
else
echo "changes=false" >> $GITHUB_OUTPUT
fi
- name: Create Pull Request with translations
if: steps.changes.outputs.changes == 'true'
uses: peter-evans/create-pull-request@4e1beaa7521e8b457b572c090b25bd3db56bf1c5 # v5
with:
token: ${{ secrets.GH_PAT }}
commit-message: "feat(i18n): update translations"
title: "feat(i18n): update translations"
body: |
## Summary
Automated weekly translation updates for documentation.
This PR was automatically created by the scheduled weekly i18n workflow, updating translations for all supported languages using Lingo.dev AI translation engine.
**Triggered**: Weekly scheduled run
**Workflow**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [x] Documentation
- [ ] Other: ___________
## Testing
This PR includes automated translations for modified English documentation content:
- 🇪🇸 Spanish (es) translations
- 🇫🇷 French (fr) translations
- 🇨🇳 Chinese (zh) translations
- 🇯🇵 Japanese (ja) translations
- 🇩🇪 German (de) translations
**What reviewers should focus on:**
- Verify translated content accuracy and context
- Check that all links and references work correctly in translated versions
- Ensure formatting, code blocks, and structure are preserved
- Validate that technical terms are appropriately translated
## Checklist
- [x] Code follows project style guidelines (automated translation)
- [x] Self-reviewed my changes (automated process)
- [ ] Tests added/updated and passing
- [x] No new warnings introduced
- [x] I confirm that I have read and agree to the terms outlined in the [Contributor License Agreement (CLA)](./CONTRIBUTING.md#contributor-license-agreement-cla)
## Screenshots/Videos
<!-- Translation changes are text-based - no visual changes expected -->
<!-- Reviewers should check the documentation site renders correctly for all languages -->
branch: auto-translate/weekly-${{ github.run_id }}
base: staging
labels: |
i18n
verify-translations:
needs: translate
runs-on: blacksmith-4vcpu-ubuntu-2404
if: always() # Run even if translation fails
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
ref: staging
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.13
- name: Cache Bun dependencies
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
~/.bun/install/cache
node_modules
**/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: |
cd apps/docs
bun install --frozen-lockfile
- name: Build documentation to verify translations
env:
DATABASE_URL: postgresql://dummy:dummy@localhost:5432/dummy
run: |
cd apps/docs
bun run build
- name: Report translation status
run: |
cd apps/docs
echo "## Translation Status Report" >> $GITHUB_STEP_SUMMARY
echo "**Weekly scheduled translation run**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
en_count=$(find content/docs/en -name "*.mdx" | wc -l)
es_count=$(find content/docs/es -name "*.mdx" 2>/dev/null | wc -l || echo 0)
fr_count=$(find content/docs/fr -name "*.mdx" 2>/dev/null | wc -l || echo 0)
zh_count=$(find content/docs/zh -name "*.mdx" 2>/dev/null | wc -l || echo 0)
ja_count=$(find content/docs/ja -name "*.mdx" 2>/dev/null | wc -l || echo 0)
de_count=$(find content/docs/de -name "*.mdx" 2>/dev/null | wc -l || echo 0)
es_percentage=$((es_count * 100 / en_count))
fr_percentage=$((fr_count * 100 / en_count))
zh_percentage=$((zh_count * 100 / en_count))
ja_percentage=$((ja_count * 100 / en_count))
de_percentage=$((de_count * 100 / en_count))
echo "### Coverage Statistics" >> $GITHUB_STEP_SUMMARY
echo "- **🇬🇧 English**: $en_count files (source)" >> $GITHUB_STEP_SUMMARY
echo "- **🇪🇸 Spanish**: $es_count/$en_count files ($es_percentage%)" >> $GITHUB_STEP_SUMMARY
echo "- **🇫🇷 French**: $fr_count/$en_count files ($fr_percentage%)" >> $GITHUB_STEP_SUMMARY
echo "- **🇨🇳 Chinese**: $zh_count/$en_count files ($zh_percentage%)" >> $GITHUB_STEP_SUMMARY
echo "- **🇯🇵 Japanese**: $ja_count/$en_count files ($ja_percentage%)" >> $GITHUB_STEP_SUMMARY
echo "- **🇩🇪 German**: $de_count/$en_count files ($de_percentage%)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "🔄 **Auto-translation PR**: Check for new pull request with updated translations" >> $GITHUB_STEP_SUMMARY
+85
View File
@@ -0,0 +1,85 @@
name: Database Migrations
on:
workflow_call:
inputs:
environment:
description: Target environment (production, staging, or dev)
required: true
type: string
workflow_dispatch:
inputs:
environment:
description: Target environment
required: true
type: choice
options:
- production
- staging
- dev
permissions:
contents: read
jobs:
migrate:
name: Apply Database Migrations
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.13
- name: Cache Bun dependencies
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
~/.bun/install/cache
node_modules
**/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
# The expression maps the explicit environment input to exactly one repo
# secret, so the job never holds another environment's database URL. An
# unknown environment resolves to empty and the guard below fails the job.
# MIGRATION_DATABASE_URL is the optional direct (non-pooled) DSN preferred
# by migrate.ts; when the secret is unset it resolves to empty and the
# script falls back to DATABASE_URL.
- name: Apply database schema changes
working-directory: ./packages/db
env:
DATABASE_URL: ${{ inputs.environment == 'production' && secrets.DATABASE_URL || inputs.environment == 'staging' && secrets.STAGING_DATABASE_URL || inputs.environment == 'dev' && secrets.DEV_DATABASE_URL || '' }}
MIGRATION_DATABASE_URL: ${{ inputs.environment == 'production' && secrets.MIGRATION_DATABASE_URL || inputs.environment == 'staging' && secrets.STAGING_MIGRATION_DATABASE_URL || '' }}
ENVIRONMENT: ${{ inputs.environment }}
run: |
if [ -z "$DATABASE_URL" ]; then
echo "ERROR: no database URL secret resolved for environment '${ENVIRONMENT}'" >&2
exit 1
fi
if [ "${ENVIRONMENT}" = "dev" ]; then
echo "Dev environment — pushing schema directly (db:push)"
# drizzle-kit push needs a TTY to resolve ambiguous renames (--force only
# covers data-loss). In CI it throws "Interactive prompts require a TTY
# terminal" but still exits 0, so the job goes green without applying the
# change. tee keeps the output live in the log; we then fail on drizzle's
# own TTY error. A genuine non-zero exit already fails via `set -e`.
bun run db:push --force < /dev/null 2>&1 | tee /tmp/db-push.log
if grep -q "Interactive prompts require a TTY terminal" /tmp/db-push.log; then
echo "ERROR: db:push needs an interactive rename decision; land it as a versioned migration instead of relying on push." >&2
exit 1
fi
else
echo "Applying versioned migrations (db:migrate)"
bun run ./scripts/migrate.ts
fi
+72
View File
@@ -0,0 +1,72 @@
name: Publish CLI Package
on:
push:
branches: [main]
paths:
- 'packages/cli/**'
permissions:
contents: read
jobs:
publish-npm:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.13
- name: Setup Node.js for npm publishing
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org/'
- name: Cache Bun dependencies
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
~/.bun/install/cache
node_modules
**/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
working-directory: packages/cli
run: bun install --frozen-lockfile
- name: Build package
working-directory: packages/cli
run: bun run build
- name: Get package version
id: package_version
working-directory: packages/cli
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
- name: Check if version already exists
id: version_check
run: |
if npm view simstudio@${{ steps.package_version.outputs.version }} version &> /dev/null; then
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Publish to npm
if: steps.version_check.outputs.exists == 'false'
working-directory: packages/cli
run: npm publish --access=public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Log skipped publish
if: steps.version_check.outputs.exists == 'true'
run: echo "Skipped publishing because version ${{ steps.package_version.outputs.version }} already exists on npm"
+92
View File
@@ -0,0 +1,92 @@
name: Publish Python SDK
on:
push:
branches: [main]
paths:
- 'packages/python-sdk/**'
permissions:
contents: write
jobs:
publish-pypi:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Setup Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.12'
cache: 'pip'
- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install build twine pytest requests tomli
- name: Run tests
working-directory: packages/python-sdk
run: |
PYTHONPATH=. pytest tests/ -v
- name: Get package version
id: package_version
working-directory: packages/python-sdk
run: echo "version=$(python -c "import tomli; print(tomli.load(open('pyproject.toml', 'rb'))['project']['version'])")" >> $GITHUB_OUTPUT
- name: Check if version already exists
id: version_check
run: |
if pip index versions simstudio-sdk | grep -q "${{ steps.package_version.outputs.version }}"; then
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Build package
if: steps.version_check.outputs.exists == 'false'
working-directory: packages/python-sdk
run: python -m build
- name: Check package
if: steps.version_check.outputs.exists == 'false'
working-directory: packages/python-sdk
run: twine check dist/*
- name: Publish to PyPI
if: steps.version_check.outputs.exists == 'false'
working-directory: packages/python-sdk
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: twine upload dist/*
- name: Log skipped publish
if: steps.version_check.outputs.exists == 'true'
run: echo "Skipped publishing because version ${{ steps.package_version.outputs.version }} already exists on PyPI"
- name: Create GitHub Release
if: steps.version_check.outputs.exists == 'false'
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: python-sdk-v${{ steps.package_version.outputs.version }}
name: Python SDK v${{ steps.package_version.outputs.version }}
body: |
## Python SDK v${{ steps.package_version.outputs.version }}
Published simstudio-sdk==${{ steps.package_version.outputs.version }} to PyPI.
### Installation
```bash
pip install simstudio-sdk==${{ steps.package_version.outputs.version }}
```
### Documentation
See the [README](https://github.com/simstudioai/sim/tree/main/packages/python-sdk) or the [docs](https://docs.sim.ai/sdks/python) for more information.
draft: false
prerelease: false
+98
View File
@@ -0,0 +1,98 @@
name: Publish TypeScript SDK
on:
push:
branches: [main]
paths:
- 'packages/ts-sdk/**'
permissions:
contents: write
jobs:
publish-npm:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.13
- name: Setup Node.js for npm publishing
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org/'
- name: Cache Bun dependencies
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
~/.bun/install/cache
node_modules
**/node_modules
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Run tests
working-directory: packages/ts-sdk
run: bun run test
- name: Build package
working-directory: packages/ts-sdk
run: bun run build
- name: Get package version
id: package_version
working-directory: packages/ts-sdk
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
- name: Check if version already exists
id: version_check
run: |
if npm view simstudio-ts-sdk@${{ steps.package_version.outputs.version }} version &> /dev/null; then
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Publish to npm
if: steps.version_check.outputs.exists == 'false'
working-directory: packages/ts-sdk
run: npm publish --access=public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Log skipped publish
if: steps.version_check.outputs.exists == 'true'
run: echo "Skipped publishing because version ${{ steps.package_version.outputs.version }} already exists on npm"
- name: Create GitHub Release
if: steps.version_check.outputs.exists == 'false'
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: typescript-sdk-v${{ steps.package_version.outputs.version }}
name: TypeScript SDK v${{ steps.package_version.outputs.version }}
body: |
## TypeScript SDK v${{ steps.package_version.outputs.version }}
Published simstudio-ts-sdk@${{ steps.package_version.outputs.version }} to npm.
### Installation
```bash
npm install simstudio-ts-sdk@${{ steps.package_version.outputs.version }}
```
### Documentation
See the [README](https://github.com/simstudioai/sim/tree/main/packages/ts-sdk) or the [docs](https://docs.sim.ai/sdks/typescript) for more information.
draft: false
prerelease: false
+193
View File
@@ -0,0 +1,193 @@
name: Test and Build
on:
workflow_call:
workflow_dispatch:
permissions:
contents: read
jobs:
test-build:
name: Test and Build
runs-on: blacksmith-8vcpu-ubuntu-2404
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.13
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: latest
- name: Mount Bun cache (Sticky Disk)
uses: useblacksmith/stickydisk@4c034ba57b706cf0e3b4b0ce098c2a3b1071580c # v1
with:
key: ${{ github.repository }}-bun-cache
path: ~/.bun/install/cache
- name: Mount node_modules (Sticky Disk)
uses: useblacksmith/stickydisk@4c034ba57b706cf0e3b4b0ce098c2a3b1071580c # v1
with:
key: ${{ github.repository }}-node-modules
path: ./node_modules
- name: Mount Turbo cache (Sticky Disk)
uses: useblacksmith/stickydisk@4c034ba57b706cf0e3b4b0ce098c2a3b1071580c # v1
with:
key: ${{ github.repository }}-turbo-cache
path: ./.turbo
- name: Restore Next.js build cache
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: ./apps/sim/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-nextjs-
- name: Install dependencies
run: bun install --frozen-lockfile
# Surfaces known CVEs in the dependency tree. Non-blocking until the
# existing advisory backlog is triaged, then flip to a required gate by
# removing continue-on-error.
- name: Security audit
run: bun audit
continue-on-error: true
- name: Validate env flags
run: |
FILE="apps/sim/lib/core/config/env-flags.ts"
ERRORS=""
echo "Checking for hardcoded boolean env flags..."
# Use perl for multiline matching to catch both:
# export const isHosted = true
# export const isHosted =
# true
HARDCODED=$(perl -0777 -ne 'while (/export const (is[A-Za-z]+)\s*=\s*\n?\s*(true|false)\b/g) { print " $1 = $2\n" }' "$FILE")
if [ -n "$HARDCODED" ]; then
ERRORS="${ERRORS}\n❌ Env flags must not be hardcoded to boolean literals!\n\nFound hardcoded flags:\n${HARDCODED}\n\nEnv flags should derive their values from environment variables.\n"
fi
echo "Checking env flag naming conventions..."
# Check that all export const (except functions) start with 'is'
# This finds exports like "export const someFlag" that don't start with "is" or "get"
BAD_NAMES=$(grep -E "^export const [a-z]" "$FILE" | grep -vE "^export const (is|get)" | sed 's/export const \([a-zA-Z]*\).*/ \1/')
if [ -n "$BAD_NAMES" ]; then
ERRORS="${ERRORS}\n❌ Env flags must use 'is' prefix for boolean flags!\n\nFound incorrectly named flags:\n${BAD_NAMES}\n\nExample: 'hostedMode' should be 'isHostedMode'\n"
fi
if [ -n "$ERRORS" ]; then
echo ""
echo -e "$ERRORS"
exit 1
fi
echo "✅ All env flags are properly configured"
- name: Check block registry invariants
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE_REF="origin/${{ github.base_ref }}"
git fetch --depth=1 origin "${{ github.base_ref }}" 2>/dev/null || true
else
BASE_REF="HEAD~1"
fi
bun run apps/sim/scripts/check-block-registry.ts "$BASE_REF"
- name: Lint code
run: bun run lint:check
- name: Enforce monorepo boundaries
run: bun run check:boundaries
- name: API contract boundary audit
run: bun run check:api-validation:strict
- name: Shared utils enforcement audit
run: bun run check:utils
- name: Zustand v5 selector audit
run: bun run check:zustand-v5
- name: React Query pattern audit
run: bun run check:react-query
- name: Client boundary import audit
run: bun run check:client-boundary
- name: Bare-icon theme-safety audit
run: bun run check:bare-icons
- name: Icon SVG path validity audit
run: bun run check:icon-paths
- name: Verify realtime prune graph
run: bun run check:realtime-prune
- name: Migration safety (zero-downtime) audit
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE_REF="origin/${{ github.base_ref }}"
git fetch --depth=1 origin "${{ github.base_ref }}" 2>/dev/null || true
else
BASE_REF="HEAD~1"
fi
bun run check:migrations "$BASE_REF"
- name: Type-check realtime server
run: bunx turbo run type-check --filter=@sim/realtime
- name: Run tests with coverage
env:
NODE_OPTIONS: '--no-warnings --max-old-space-size=8192'
NEXT_PUBLIC_APP_URL: 'https://www.sim.ai'
DATABASE_URL: 'postgresql://postgres:postgres@localhost:5432/simstudio'
ENCRYPTION_KEY: '7cf672e460e430c1fba707575c2b0e2ad5a99dddf9b7b7e3b5646e630861db1c' # dummy key for CI only
TURBO_CACHE_DIR: .turbo
run: bun run test
- name: Check schema and migrations are in sync
working-directory: packages/db
run: |
bunx drizzle-kit generate --config=./drizzle.config.ts
if [ -n "$(git status --porcelain ./migrations)" ]; then
echo "❌ Schema and migrations are out of sync!"
echo "Run 'cd packages/db && bunx drizzle-kit generate' and commit the new migrations."
git status --porcelain ./migrations
git diff ./migrations
exit 1
fi
echo "✅ Schema and migrations are in sync"
- name: Build application
env:
NODE_OPTIONS: '--no-warnings --max-old-space-size=8192'
NEXT_PUBLIC_APP_URL: 'https://www.sim.ai'
DATABASE_URL: 'postgresql://postgres:postgres@localhost:5432/simstudio'
STRIPE_SECRET_KEY: 'dummy_key_for_ci_only'
STRIPE_WEBHOOK_SECRET: 'dummy_secret_for_ci_only'
RESEND_API_KEY: 'dummy_key_for_ci_only'
AWS_REGION: 'us-west-2'
ENCRYPTION_KEY: '7cf672e460e430c1fba707575c2b0e2ad5a99dddf9b7b7e3b5646e630861db1c' # dummy key for CI only
TURBO_CACHE_DIR: .turbo
run: bunx turbo run build --filter=sim
- name: Upload coverage to Codecov
uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5
with:
directory: ./apps/sim/coverage
fail_ci_if_error: false
verbose: true