b768441c13aed1c978522f59d2cc326f3bd5a708
427 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
de610bc4e7 |
Rename CI New UI workflow to CI UI (#22030)
Renames the `CI New UI` workflow to `CI UI`, dropping the "new ui" terminology everywhere it appeared. - Renamed `.github/workflows/ci-new-ui.yaml` → `ci-ui.yaml` - Updated the workflow `name`, job names (`ui-task`, `ui-sb-build`, `ui-sb-test`, `ci-ui-status-check`), and internal `needs`/`if` references - Updated `visual-regression-dispatch.yaml` which keys off the workflow name (`CI UI`) Note: the required status check in branch protection settings (workflow name / `ci-ui-status-check`) lives in repo settings and will need updating by an admin so PRs don't wait on the old check name. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22030?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
6055262012 |
Deploy website only when twenty-website changes (#21977)
## Problem Every push to `main` redeploys the website. `cd-deploy-main.yaml` dispatches the infra `auto-deploy-main` fan-out, which unconditionally triggered `deploy-website`. Since most PRs don't touch `packages/twenty-website/**`, the majority were full, identical Cloudflare builds — wasted CI and noise. ## Fix Detect website changes here (using the existing reusable `changed-files.yaml`) and pass the result as a `deploy_website` input on the **single** `auto-deploy-main` dispatch: - New `website-changed-files` job checks `packages/twenty-website/**`. - The existing `auto-deploy-main` dispatch now carries `-f deploy_website=<true|false>`. - This repo keeps triggering **only** `auto-deploy-main` — it never dispatches `deploy-website` directly. `twenty-infra` decides whether to run the website deploy (per @FelixMalfait's review: the public repo shouldn't be able to run arbitrary `twenty-infra` workflows directly). - Server/front deploy is **unchanged** — still every merge. ## Paired change & merge order Companion PR: **twentyhq/twenty-infra#747** — adds the `deploy_website` input to `auto-deploy-main` and gates the website dispatch on it. **Merge twenty-infra#747 FIRST**, then this one. (If this merges first, it would pass an input the old `auto-deploy-main` doesn't accept, failing the dispatch. Infra-first only delays website auto-deploys until this lands — no breakage.) |
||
|
|
1646bdf35e |
Add twenty-partners on internal ci apps (#21975)
as title <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21975?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
3030b7d0e5 |
Add people-data-labs on internal ci apps (#21941)
Add people-data-labs to internal apps CI: remove from CI_EXCLUDED_APPLICATIONS and unify config with twenty-discord/twenty-slack. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21941?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
64385842bb |
Add twenty-linear on internal ci apps (#21942)
Add twenty-linear to internal apps CI: remove from CI_EXCLUDED_APPLICATIONS and unify config with twenty-discord/twenty-slack. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21942?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
4b868f9b29 |
Add twenty-for-twenty on internal ci apps (#21944)
Add twenty-for-twenty to internal apps CI: remove from CI_EXCLUDED_APPLICATIONS and unify config with twenty-discord/twenty-slack. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21944?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
8b9e3a0fc3 |
Add self-hosting on internal ci apps (#21940)
Add self-hosting to internal apps CI: remove from CI_EXCLUDED_APPLICATIONS and unify config with twenty-discord/twenty-slack. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21940?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
b354df3c59 |
Add twenty-fireflies on internal ci apps (#21939)
Add twenty-fireflies to internal apps CI: remove from CI_EXCLUDED_APPLICATIONS and unify config with twenty-discord/twenty-slack. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21939?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
cb5d64fefc |
Add twenty-exa application to internal app ci (#21882)
renamed exa to twenty-exa add twenty-exa to ci check <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21882?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
584c567a7f |
Add twenty-discord on internal ci apps (#21928)
add twenty-discord to ci check <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21928?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
153e41e036 |
ci: block bot contributors from PR commit history (#21926)
## What Adds a CI check (`Blocked Contributors Check`) that runs on every PR and **fails** if any commit is attributed to a known bot — via the commit author, committer, or a `Co-Authored-By:` trailer. Goal: keep automated agents (Claude, Cursor, Copilot, …) out of Twenty's contributor history. ## How - On `pull_request` (`opened`, `synchronize`, `reopened`) it fetches all PR commits via the GitHub API and matches author/committer name+email and the full commit message (for trailers) against an editable blocklist. - Patterns target **bot identities** (emails / `[bot]` handles), **not** bare first names — so a human contributor named "Claude" is *not* flagged. - On failure it emits `::error::` annotations naming the offending SHA + what matched, plus remediation guidance (rebase with `--reset-author`, strip trailers, force-push). Current blocklist: ``` noreply@anthropic.com @anthropic.com cursoragent@cursor.com copilot-swe-agent[bot] ``` Add a line to block another bot — no logic changes needed. ## Notes - This workflow only *reports* a failed status. To actually block merges, add **Blocked Contributors Check** as a required status check in branch-protection rules for `main` (repo Settings → Branches). - `@anthropic.com` also blocks any Anthropic-domain identity; narrow to just `noreply@anthropic.com` if real Anthropic employees may contribute under their work email. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21926?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
a870e034a6 |
Add twenty slack to internal application ci (#21849)
- adds `twenty-slack` to internal application ci - unify config with twenty-last-contact app - add base oxlint config to show error twenty-shared is used in internal app <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21849?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
576f88b5c5 |
Update ci internal applications (#21837)
Fix `twenty-last-contact` ci - add tests - add tsgo - update package commands <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21837?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
8f7d7101ff |
Add application to test input in workflow (#21830)
https://github.com/twentyhq/twenty/pull/21791 follow up |
||
|
|
5a6c02a7aa |
Create CI workflow for internal apps (#21791)
as title <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21791?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
b063c7850b |
Twenty app e2e app prod parity dispatch (#21750)
# Introduction On main merge or if PR is labelled with specific label, dispatch the app prod parity check Note: for the moment not optimal for PR context as it will only set a status check on the related commit which is not blocking anything for the moment related https://github.com/twentyhq/core-team-issues/issues/2557 <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21750?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
495907c781 |
ci: remove merge queue, run e2e on push to main (#21722)
## What Removes the GitHub merge queue and runs what the queue used to gate — the E2E (Playwright) suite — directly on push to `main`. If that run fails on `main`, we ping engineering via webhook. ## Why In the queue, only the `e2e-test` job in `ci-merge-queue.yaml` ran real work — every other CI workflow's `merge_group` path skipped its `changed-files-check` and tests, so the queue's status checks for those were effectively green no-ops. The expensive thing actually gated was E2E. Moving it to `push: main` validates the merged state post-merge without the queue's batching overhead. ## Changes - **Rename** `ci-merge-queue.yaml` → `ci-e2e-main.yaml` (`name: CI E2E Main`). - `e2e-test` now triggers on `push` to `main` (the `run-merge-queue` PR label is kept as a manual opt-in for running E2E on a PR). - Status-check job renamed `ci-e2e-main-status-check`. - New `notify-main-ci-failure` job: on a failed **main push**, `POST`s to `https://engineering.twenty.com/s/main-ci-failing` with the commit SHA, actor, and run URL. - **Strip dead merge-queue config** from the other CI workflows: removed the `merge_group:` triggers and the now-unreachable `if: github.event_name != 'merge_group'` guards from `ci-server`, `ci-shared`, `ci-sdk`, `ci-front-component-renderer`, `ci-test-docker-compose`, `ci-website`, and the `merge_group:` trigger from `ci-front`, `ci-ui`, `ci-new-ui`. ## Required follow-up (not in this PR) The merge queue itself is a **repo setting**, not code. After this merges, disable **"Require merge queue"** on the `main` ruleset/branch protection (Settings → Rules), otherwise GitHub keeps batching. Required status checks tied to the old queue should also be dropped/updated. ## Behavior change E2E now runs **after** merge rather than blocking it in the queue — a bad change lands on `main` and then alerts (the webhook is the mitigation), instead of being held back pre-merge. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21722?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
66c860574f |
Point New UI visual regression at the twenty-ui Argos project (#21728)
The `twenty-new-ui` Argos project is being renamed to `twenty-ui` (and
the old `twenty-ui` / `twenty-ui-vs-new-ui` projects removed).
Updates the New UI visual-regression flow to target `twenty-ui`: the
dispatch project mapping and the screenshot artifact name (which must
match `argos-screenshots-${project}`), plus the internal storybook
artifact name for consistency.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21728?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
|
||
|
|
9c9c34fccf |
Remove twenty-ui-deprecated and migrate frontend to twenty-ui (#21596)
Migrates `twenty-front`, `twenty-sdk`, and `twenty-front-component-renderer` from `twenty-ui-deprecated` to `twenty-ui` (mechanical import swap — the packages have API parity) and deletes the deprecated package along with its workspace/CI/config wiring. Also adds `@linaria/react`/`@linaria/core` as direct deps of `twenty-front` (it used them transitively via the deprecated package). Note: move the required status check from `ci-ui-status-check` to `ci-new-ui-status-check`. Argos: the Storybook box-model/button-reset baseline shift (the bulk of the visual diffs) is isolated in #21665 — Storybook now loads twenty-ui's global `reset.scss`, which the production app already ships. Once #21665 merges and this branch is rebased, the remaining Argos diffs are component-level visual-parity items only. |
||
|
|
d5c7b735d2 |
ci: migrate cross-repo dispatch senders to workflow_dispatch (actions:write) (#21648)
# Introduction Getting rid of the fine grained PAT used to dispatch to internal repositories. Repo dispatch requires the contents write permissions which is too wide for such use Refactored all senders and target to pass through a workflow dispatch instead Creating a centralize app that forges a token with actions: write only provided permissions to mitigate any token exfiltrations |
||
|
|
12b1dba986 |
Add call recording scheduling backend (#21629)
This PR adds the backend scheduling slice for call recording. It wires the `twenty-meeting-bot` internal app to reconcile calendar events, calendar-channel associations, and workspace member auto-record preference changes, then schedule, cancel, or reschedule Recall bots based on the resulting policy. It also adds the needed calendar-channel owner lookup support, generated metadata updates, app config/default role updates, unit tests, and CI for the internal app. Coming next: - Recall webhook handling and signature validation - Stale-state convergence for failed Recall cleanup/recreate cases - Media, transcript, audio, and video ingestion - Billing charge flow - Frontend/settings UI for recording controls <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21629?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
97871131a1 |
fix(server): mitigate integration-test OOM flakiness (#21588)
## Problem `server-integration-test` shards have been failing intermittently across unrelated PRs with a distinctive signature: the shard exits code 1 with **no jest assertion failure, no `Test Suites:` summary, and no V8 `JavaScript heap out of memory` error** — the process just dies mid-run. Failures hit random shards and clear on re-run (e.g. an unrelated branch failed shard 6 once, then passed 3× on identical code), while the `merge_group` gate stays green. ### Root cause Each shard runs a **single in-band jest process** that boots one shared NestJS app (`globalSetup` → `app.listen`) and holds it for the entire shard, driving heavy metadata migrations + cache rebuilds in that one process. `NODE_OPTIONS=--max-old-space-size=12288` let V8 grow to 12 GB — *above* the `ubuntu-latest` runner's available RAM (16 GB, shared with Postgres/Redis/ClickHouse). V8 therefore deferred aggressive GC and grew past physical memory, so the **OS OOM-killer killed the process before V8 hit its own ceiling** — which is why there's no heap error and no jest summary, just a silent exit. ## Changes (CI/test-only — prod runtime untouched) - **Lower the integration jest heap cap `12288` → `6144`** so V8 self-limits below physical headroom instead of being OS-killed. Counterintuitively safer: a real leak now surfaces as a *visible* heap error naming the test, rather than a silent death. (`database:reset` keeps 12288 — it runs alone, before jest.) - **Add `--logHeapUsage`** to the integration jest runs to expose the per-file heap trend for confirming/pinpointing the growth. - **Split integration tests across 16 shards (was 10)** to lower the peak working set per shard. - **Make perf logging a first-class `LoggerService` tool** (per @prastoin's review): add `LoggerService.perf()` and unify the existing `time()`/`timeEnd()` helpers into `perfTime()`/`perfTimeEnd()` (now routed through the driver), all gated by a new `PERF_LOG_ENABLED` config var. It **defaults on** so real environments keep emitting the install-perf logs, and `.env.test` sets it `false` to mute the per-action flood in integration tests. The `application-manifest` and `validate-build` services were moved from the built-in `Logger` to `LoggerService` to use it. ## Notes - `--max-old-space-size` lives only in the `test:integration` nx target; it is **not** the prod server heap setting, so prod is unaffected. - This is mitigation. If `--logHeapUsage` shows monotonic growth across files, there's a real accumulation in the long-lived app (retained flat-maps / metadata cache) worth a follow-up heap-snapshot fix. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21588?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
9884769ce4 |
fix(ci): bump claude-code-action to v1.0.146 (CVE-2026-47751) (#21499)
## What Bumps both \`anthropics/claude-code-action\` pins in \`.github/workflows/claude.yml\` from the floating \`v1\` SHA (\`dde2242\`) to \`v1.0.146\` (\`ac7e24b\`). ## Why The old pin predates the fix for **CVE-2026-47751** (Tenable TRA-2026-27, CVSSv4 5.3): claude-code-action checks out the PR head branch and unconditionally sets \`enableAllProjectMcpServers: true\`, so an attacker could ship a malicious \`.mcp.json\` in a PR branch and get arbitrary command execution in the runner — with access to workflow secrets — once a privileged user triggers the action. Fixed upstream in **claude-code-action 1.0.78** (released 2026-03-24). This pins to the current release, v1.0.146. ## Notes - \`claude.yml\` is the only workflow in the repo referencing the action; both job invocations (\`claude\` and \`claude-cross-repo\`) were updated. - All existing \`with:\` inputs remain valid in v1.0.146 — no deprecated args. Ref: https://www.tenable.com/security/research/tra-2026-27 <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21499?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
79f7c96939 |
Move Claude workflow concurrency to job level so PR chatter can't cancel queued runs (#21498)
## Problem A second `@claude` request on a PR while a Claude run is already in progress gets silently cancelled. Concrete case on #21443: [this comment](https://github.com/twentyhq/twenty/pull/21443#discussion_r3404037004) ("@claude please investigate and report", 14:24:28) produced [a run](https://github.com/twentyhq/twenty/actions/runs/27421867558) that was cancelled 3 seconds after creation, while [the run for an earlier comment](https://github.com/twentyhq/twenty/actions/runs/27421856742) was still in progress. Claude never responded. ## Root cause The `concurrency` block is declared at the **workflow** level, keyed on the PR number. Two GitHub Actions behaviors combine badly here: 1. A concurrency group holds at most one running + **one pending** run; every new run entering the group cancels the previously pending one (`cancel-in-progress: false` only protects the *running* run). 2. Workflow-level concurrency is acquired **before** job-level `if` conditions are evaluated — so every `issue_comment` / `pull_request_review_comment` / `pull_request_review` event on the PR enters the group, even ones with no `@claude` that end up skipped. So while a Claude run is in progress, any PR activity evicts the queued `@claude` run. It's even self-defeating: a review-thread reply fires *two* webhook events (`pull_request_review_comment` + a companion `pull_request_review` with an empty body), so the companion event cancels the queued comment run ~2s later. Claude's own "finished" reply also fires events that kill whatever is queued. ## Fix Move concurrency to the **job** level. A job whose `if` evaluates false is skipped before it ever requests the concurrency slot, so only genuine `@claude` jobs enter the queue. Real Claude runs on the same PR are still serialized (no parallel pushes to the same branch). Also gives `claude-cross-repo` its own group keyed on source repo + issue number — previously a cross-repo dispatch for issue N shared a group with PR N in this repo and they could needlessly queue behind each other. ## Remaining limitation GitHub keeps only one pending job per group: posting three `@claude` requests while the first is still running will still cancel the second when the third arrives. Zero-loss queueing would require a unique group per comment, which would allow concurrent runs pushing to the same PR branch — not worth it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21498?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
c4453923f0 |
Update CI: Argos visual regression for twenty-front storybook (#21454)
## What Adds Argos visual regression for `twenty-front`, reusing the storybook CI already builds and the existing sharded test matrix. Stories in the `modules` and `pages` scopes are captured as PNGs during `front-sb-test`, merged into one artifact, and pixel-diffed against `main` on the self-hosted Argos with results posted as a PR comment — same pipeline as `twenty-ui` (#21210 / #21262). ## How - **Capture**: `@argos-ci/storybook` vitest plugin, same setup as `twenty-ui`. Skipped for `performance` stories (nondeterministic profiling reports). Freezes framer-motion to avoid flaky diffs (#21412). - **Sharding**: each modules/pages shard uploads a partial artifact; a new `front-sb-screenshots` job merges them into `argos-screenshots-twenty-front` (`overwrite: true` so re-runs work). - **Baselines**: `CI Front` now runs on `push: main` — Argos resolves base builds by exact merge-base commit, so every main commit needs a build (#21217/#21222 pattern). Main pushes get a per-SHA concurrency group so back-to-back merges can't cancel queued runs and leave baseline gaps; the `performance` scope is dropped on push. - **Dispatch**: `visual-regression-dispatch.yaml` watches `CI Front` → `project=twenty-front`. ## Rollout - ✅ Prod Argos project `twenty-front` created (id 68) + `ARGOS_TOKEN_FRONT` secret set - ⬜ Merge the twentyhq/ci-privileged companion PR **before** this one - First PR builds show as *orphan* until the first main push creates a baseline (expected, same as the twenty-ui rollout) |
||
|
|
56e1d886d8 |
Add CI workflow for people data labs app (#21487)
Adds a dedicated CI workflow for the People Data Labs app that runs lint, typecheck, and unit tests only when files under `packages/twenty-apps/internal/people-data-labs/` change. The app is a standalone yarn project (its own lockfile, pinned published SDKs), so it isn't covered by the existing package CI workflows. The workflow gates on the app folder via the reusable `changed-files.yaml`, installs dependencies inside the app directory, and runs `yarn lint`, `yarn typecheck`, and `yarn test`. A status-check job aggregates results and stays green on skips, so it's safe to mark as a required check. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21487?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
c596a5e342 |
Rename twenty-ui to twenty-ui-deprecated and twenty-new-ui to twenty-ui to prepare package release (#21315)
## Description Promotes the next-gen UI library (formerly `twenty-new-ui`) to the name **`twenty-ui`** (v0.1.0, publishable) and renames the old package to **`twenty-ui-deprecated`**. Rewrites ~1,730 `twenty-ui` imports → `twenty-ui-deprecated`, updates all configs/CI/Docker/deps, and migrates twenty-front's `Toggle` to the new package (first consumer) as a drop-in. ## Next steps - Wire the `ui/v*` publish dispatch (`cd-deploy-tag.yaml` + `.yarnrc.yml`), then tag `ui/v0.1.0` to publish. - Continue migrating components from `twenty-ui-deprecated` → `twenty-ui`. |
||
|
|
b0d29689d2 |
feat: add Argos visual regression for twenty-new-ui (#21262)
## Summary - Add `ci-new-ui.yaml` workflow mirroring `ci-ui.yaml` for `twenty-new-ui` (lint, typecheck, test, Storybook build, Storybook test with screenshot capture) - Update `visual-regression-dispatch.yaml` to watch both `CI UI` and `CI New UI` workflows, with dispatches for three Argos projects: 1. **Self-hosted twenty-ui pixel diff** (existing, unchanged) 2. **Self-hosted twenty-new-ui pixel diff** (new) -- standard regression against main 3. **Self-hosted twenty-ui vs twenty-new-ui comparison** (new) -- cross-package visual parity - Add "Visual regression" documentation section to `twenty-new-ui/README.md` with local dev workflow (argos-tunnel via super CLI + `storybook:visual-diff`) - Resolve open question 4 in README (Argos confirmed as visual regression tool) ## Companion PR Requires companion PR on `twentyhq/ci-privileged` for the new `visual-regression-cloud` dispatch handler, upload script, and post-comment logic. ## Manual setup After merging both PRs, create two Argos projects on argos.twenty-internal.com: - `twenty-new-ui` (pixel diff) - `twenty-ui-vs-new-ui` (cross-package comparison, auto-approved branch: main) Add secrets `ARGOS_TOKEN_NEW_UI` and `ARGOS_TOKEN_COMPARISON` to ci-privileged. ## Test plan - [ ] Verify `CI New UI` workflow triggers on twenty-new-ui changes - [ ] Verify screenshot artifact `argos-screenshots-twenty-new-ui` is uploaded - [ ] Verify dispatch sends `visual-regression-cloud` events to ci-privileged - [ ] Verify existing `CI UI` → self-hosted Argos flow is unchanged |
||
|
|
a78b319877 |
sdk/v* twenty/v* namespaces (#21247)
# Introduction Removed never used release dispatch workflow Now assuming that anyone releasing will create both twenty and npm family tags Will create a workflow to ease this later We will now start to have several github releases, one per namespace |
||
|
|
cd540098f1 |
fix: pass reference_commit to Argos to resolve orphan PR builds (#21245)
## Summary - Fixes Argos CI builds showing as "Orphan" (no reference branch) for PR builds - Computes the merge-base SHA between the PR head and `main` using the GitHub API (`compareCommitsWithBasehead`) in the dispatch workflow - Passes `reference_commit` in the `ci-privileged` dispatch payload so it can be forwarded to the Argos upload API ## Context PR builds on Argos were showing as "Orphan" because `ci-privileged` (where the actual Argos upload happens) has no git history of the `twenty` repo — it cannot compute the merge-base locally. Without a `referenceCommit`, Argos can't determine which `main` build to compare against. The local `visual-diff.sh` script already passes `ARGOS_REFERENCE_COMMIT` via `git merge-base HEAD main`, but the CI pipeline was missing this. This PR adds equivalent logic using the GitHub API (no checkout needed). ## Note for ci-privileged The `upload-to-argos.ts` script in `ci-privileged` needs a corresponding update to read `reference_commit` from the dispatch payload and pass it as `referenceCommit` in the Argos API call: ```typescript referenceCommit: process.env.REFERENCE_COMMIT || undefined, ``` ## Test plan - [ ] Verify the workflow runs successfully on a PR (merge-base step computes a SHA) - [ ] Confirm Argos PR builds are no longer marked as "Orphan" after the ci-privileged counterpart is updated |
||
|
|
badeaddd37 |
fix(ci): ensure ui-sb-test runs on push to main (#21222)
## Summary - Add explicit `if: always() && needs.ui-sb-build.result == 'success'` to `ui-sb-test` job ## Context After merging #21217, the main-branch Argos baseline pipeline doesn't work: `ui-sb-test` is silently skipped on push to main, so no `argos-screenshots-twenty-ui` artifact is produced. **Root cause:** `changed-files-check` is skipped on push events (PR-only). `ui-sb-build` handles this with `if: always() && ...`, but `ui-sb-test` has no explicit `if` — GitHub Actions propagates the skip through the transitive dependency chain (`changed-files-check` → `ui-sb-build` → `ui-sb-test`). ## Test plan - Merge this PR and verify the next push to main produces the `argos-screenshots-twenty-ui` artifact - Verify `dispatch-main` successfully triggers ci-privileged with the artifact |
||
|
|
9042e8a542 |
feat(ci): Argos main baselines + local visual diff support (#21217)
## Summary **CI: Main-branch Argos baselines** - Run storybook build + screenshot capture on `push` to `main` in CI UI workflow - Add `dispatch-main` job in visual regression dispatch to forward main-branch screenshots to ci-privileged - Simplify `dispatch-pr` by inlining the artifact name and removing unused `project` output **Local visual diff support** - Add `scripts/visual-diff.sh` for running Argos uploads locally via tunnel - Add `storybook:visual-diff` Nx target wrapping the script (depends on `storybook:build`) - Honor `STORYBOOK_URL` env in `vitest.config.ts` to reuse pre-served static builds (mirrors twenty-front pattern) - Support `ARGOS_BUILD_NAME`, `ARGOS_REFERENCE_BRANCH` env overrides in vitest plugin config ## Context Argos builds on PRs are all "Orphan" because there's no reference build on `main` to compare against. The CI changes add the missing piece: every merge to main now produces screenshots and uploads them to Argos as reference builds. The local visual diff script enables developers to run visual regression checks from their machine against the self-hosted Argos instance via `kubectl port-forward` (set up by the twenty-infra `argos-tunnel` command). ## Related - twentyhq/twenty-argos#1 (backend config for self-hosted HTTPS redirect) - twentyhq/twenty-infra#709 (argos-tunnel super CLI command + self-hosted mode) ## Test plan - [ ] Verify CI UI runs on next push to main and produces the `argos-screenshots-twenty-ui` artifact - [ ] Verify `dispatch-main` triggers and uploads screenshots to Argos - [ ] Verify subsequent PR builds show diffs against the main baseline instead of "Orphan" - [ ] Run `ARGOS_TOKEN=<token> npx nx storybook:visual-diff twenty-ui` locally with tunnel active |
||
|
|
b53f1832d8 |
feat(ci): simplify visual regression dispatch to twenty-ui only (#21215)
## Summary - Only trigger visual regression on `CI UI` workflow (drop `CI Front`) - Remove tarball re-packaging step — `ci-privileged` now downloads the artifact directly via GitHub API - Remove `mode`/`project` parameters from the dispatch payload (hardcoded to twenty-ui in ci-privileged) - Pass `run_id` of the triggering CI UI workflow so ci-privileged can fetch the correct artifact ## Context Part of the fast visual regression CI initiative. The `ci-privileged` workflow has been simplified to only handle `twenty-ui` screenshots uploaded directly to Argos. ## Test plan - [x] Full E2E verified on production: screenshots → Argos build → diff results → PR comment |
||
|
|
2ac515894b |
feat(settings): add Logs as a dedicated tab in General settings (#21180)
## What & why The audit-log viewer lived as a full-screen page reachable only via a "View Logs" button buried in the **Security** tab. This surfaces it as the **third tab in General settings** (`General | Security | Logs`), consistent with the other tabs. ## Changes - **Relocated** the event-logs module `pages/settings/security/event-logs/` → `modules/settings/event-logs/` and render it as tab content instead of a `FullScreenContainer` page. Dropped `SettingsPath.EventLogs`, its route, and the fullscreen handling in favor of the `general#logs` hash tab. - **Security tab:** removed the "View Logs" entry; kept the log-retention setting there. - **In-tab gating** (shown to users with the Security permission): Enterprise upgrade card when not entitled, a clear "ClickHouse not configured" placeholder otherwise (derived from client config), and the query is skipped when disabled. Replaces a bespoke error component that string-matched error messages with the shared `SettingsEmptyPlaceholder` / `SettingsEnterpriseFeatureGateCard`. - **Layout:** boxed content column with the table selector + filters grouped in a `Card` and the results table below, matching settings conventions. Kept the existing fixed filters (page/event name, member, period) rather than recreating the record-view filter chips (those are tightly coupled to record/view context). Frontend + `twenty-shared` only — no changes to the log query or data. ## Test plan - [x] `npx nx typecheck twenty-front` and `npx nx lint twenty-front` pass - [x] Settings → General shows three tabs; Logs is the third; breadcrumb stays "Workspace / General" - [x] With Enterprise + ClickHouse: table selector, filters, refresh, and the paginated table work - [x] Non-Enterprise: Enterprise upgrade card shown; no failing query fires - [ ] Enterprise without ClickHouse: shows the "ClickHouse not configured" placeholder - [ ] Security tab still shows the log-retention setting and the "View Logs" button is gone - [ ] A user without the Security permission sees neither the Security nor Logs tab |
||
|
|
e6614299c6 |
feat(ci): integrate Argos visual regression via vitest screenshots (#21210)
## Summary
- Adds `@argos-ci/storybook` vitest plugin to `twenty-ui` for automatic
screenshot capture during vitest storybook tests
- Uploads captured screenshots (PNG, ~5MB) as a CI artifact instead of
passing the full storybook build
- Updates the visual regression dispatch workflow to pass
`mode=argos-screenshots` to ci-privileged, which then uploads
screenshots to Argos via CLI
This replaces the 10-minute Storybook screenshot capture with a ~30s
vitest browser-mode approach. The heavy screenshot work happens on free
public runners, while ci-privileged only handles the Argos API upload
(keeping secrets private).
## Architecture
```
twenty (public, free runners) ci-privileged (private)
───────────────────────────── ────────────────────────
1. Build storybook-static 4. Download screenshots artifact
2. Vitest captures screenshots 5. `argos upload` → Argos API
3. Upload screenshots artifact 6. Poll for results
7. Post PR comment
```
## Test plan
- [x] Verified locally: vitest captures 225 screenshots in ~28s
- [x] Verified `@argos-ci/cli upload` successfully creates Argos build
from captured screenshots
- [x] Argos diffs computed and results visible via API
- [ ] CI runs end-to-end on a PR
|
||
|
|
0671ff3de5 |
Fix lambda error (#21179)
- move twenty-sdk from dependencies to devDependencies - add documentation about breaking - add warning about moving the package to dev dependencies |
||
|
|
1642be86f5 |
Bonapara/twenty codex plugin (#20857)
@martmull v2.0 ;) --------- Co-authored-by: martmull <martmull@hotmail.fr> Co-authored-by: bosiraphael <raphael.bosi@gmail.com> |
||
|
|
9b54200d8c |
Fix playwright CI (#21024)
## Context
The Install Playwright step ran npx playwright install with no
arguments, which downloads all browsers (Chromium + Firefox + WebKit +
ffmpeg, ~500MB+) on every run with no caching.
Fix:
- Install Chromium only — npx playwright install chromium instead of all
browsers.
- Cache the browser binaries — actions/cache on ~/.cache/ms-playwright,
keyed on the resolved Playwright version (v4-playwright-browsers-${{
runner.os }}-<version>). On a cache hit the install step is skipped
entirely; the cache invalidates automatically when the Playwright
version bumps.
|
||
|
|
2f4ebf8160 |
Move preview environment workflow to ci-privileged (#20872)
## Summary Slims `preview-env-dispatch.yaml` to a single dispatch and deletes `preview-env-keepalive.yaml`. The actual preview-env work moves to **twentyhq/ci-privileged#22** (must merge as a pair). ## Why Context: PR #20867 was a credential-exfil attempt against our workflows. GitHub's default fork-PR-no-secrets policy + our existing gates (`author_association` checks, `pull_request_target` checking out base, `enableScripts: false`) neutralized the actual attack — but the audit surfaced one workflow that *would* have given a malicious external PR access to a real secret if a maintainer had applied the `preview-app` label: `preview-env-keepalive.yaml`. That workflow checked out the PR head SHA, did `docker login` with `DOCKERHUB_PASSWORD`, then ran the PR's `docker-compose.yml`. A malicious compose could have mounted `~/.docker/config.json` and exfiltrated the Dockerhub credential. After this PR, that workflow lives in `twentyhq/ci-privileged` instead, paired with a rename of the credential to `DOCKERHUB_RO_TOKEN` (Dockerhub PAT with `Public Repo Read-only` scope). A read-only PAT has no exfiltration value — it's equivalent to anonymous Dockerhub access plus rate-limit headroom — so the credential lives safely on the runner without further hygiene tricks. ## What this PR does - **Modifies** `.github/workflows/preview-env-dispatch.yaml`: - Single dispatch to `twentyhq/ci-privileged` (was: self-dispatch to twenty for the env + a separate dispatch to ci-privileged for the PR comment). - `permissions: {}` (was: `contents: write`). - Drops `preview-env-keepalive.yaml` from the path-trigger list. - **Deletes** `.github/workflows/preview-env-keepalive.yaml`. The 207-line workflow now lives in `twentyhq/ci-privileged/.github/workflows/preview-env.yaml`. Net `twenty` repo change: **-204 lines / +3 lines**. ## Companion PR twentyhq/ci-privileged#22 — adds the new `preview-env.yaml`, deletes the now-redundant `post-preview-comment.yaml`. ## Secrets fallout in this repo After this PR, `DOCKERHUB_PASSWORD` in `twentyhq/twenty` secrets is only used by `ci-test-docker-compose.yaml`, where: - It evaluates to empty for fork PRs (GitHub default — secrets aren't passed to fork-PR workflows). - It's only needed for internal / merge_queue runs, for Dockerhub rate-limit headroom on base-image pulls. Recommend (separate change): also convert the twenty-side `DOCKERHUB_PASSWORD` to a `Public Repo Read-only` Dockerhub PAT, and rename it to `DOCKERHUB_RO_TOKEN` for consistency with ci-privileged. The workflow change for `ci-test-docker-compose.yaml` would just be a rename — login flow is identical for password vs. PAT. ## Test plan - [ ] Merge twentyhq/ci-privileged#22 first (so the dispatched event has a handler) - [ ] Open an internal PR touching `packages/twenty-docker/**`, confirm `Preview Environment Dispatch` runs and ci-privileged's `Preview Environment` workflow runs the docker compose + posts the URL - [ ] On an external contributor PR, apply the `preview-app` label, confirm the same flow - [ ] Confirm closing the PR doesn't break (no cleanup workflow was changed) |
||
|
|
056e3a4cd8 |
Add check for breaking api changes (#20848)
- update ci-breaking-changes.yaml so it check for api contrat breaks - check fails properly when removing fix https://github.com/twentyhq/twenty/pull/20825 - check it turns green again when adding fix back |
||
|
|
237a943947 |
Update twenty sdk commands (#20735)
Performs twenty-sdk cli command migration: Summary ``` ┌─────┬──────────────────────────┬────────────────────────────┬───────────────────────┐ │ # │ Old command │ New command │ Status │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 1 │ twenty dev [appPath] │ twenty dev [appPath] │ Unchanged (now also │ │ │ │ │ DEFAULT) │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 2 │ twenty dev --once │ twenty dev --once │ Unchanged │ │ │ [appPath] │ [appPath] │ │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 3 │ twenty dev --watch │ twenty dev [appPath] │ --watch flag removed │ │ │ [appPath] │ │ (was default) │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 4 │ twenty dev --verbose │ twenty dev --verbose │ Unchanged │ │ │ [appPath] │ [appPath] │ │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 5 │ twenty dev --debug │ twenty dev --debug │ Unchanged │ │ │ [appPath] │ [appPath] │ │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 6 │ twenty dev --debounceMs │ twenty dev --debounceMs │ Unchanged │ │ │ <ms> [appPath] │ <ms> [appPath] │ │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 7 │ twenty build [appPath] │ twenty dev:build [appPath] │ Deprecated → colon │ │ │ │ │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 8 │ twenty build --tarball │ twenty dev:build --tarball │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 9 │ twenty typecheck │ twenty dev:typecheck │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 10 │ twenty logs [appPath] │ twenty dev:fn-logs │ Deprecated → colon │ │ │ │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 11 │ twenty logs -n <name> │ twenty dev:fn-logs -n │ Deprecated → colon │ │ │ [appPath] │ <name> [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 12 │ twenty logs -u <id> │ twenty dev:fn-logs -u <id> │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 13 │ twenty exec [appPath] │ twenty dev:fn-exec │ Deprecated → colon │ │ │ │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 14 │ twenty exec -n <name> │ twenty dev:fn-exec -n │ Deprecated → colon │ │ │ [appPath] │ <name> [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 15 │ twenty exec -u <id> │ twenty dev:fn-exec -u <id> │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 16 │ twenty exec -p <json> │ twenty dev:fn-exec -p │ Deprecated → colon │ │ │ [appPath] │ <json> [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 17 │ twenty exec │ twenty dev:fn-exec │ Deprecated → colon │ │ │ --postInstall [appPath] │ --postInstall [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 18 │ twenty exec --preInstall │ twenty dev:fn-exec │ Deprecated → colon │ │ │ [appPath] │ --preInstall [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 19 │ twenty add [entityType] │ twenty dev:add │ Deprecated → colon │ │ │ │ [entityType] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 20 │ twenty add --path <path> │ twenty dev:add --path │ Deprecated → colon │ │ │ [entityType] │ <path> [entityType] │ command │ └─────┴──────────────────────────┴────────────────────────────┴───────────────────────┘ App lifecycle commands ┌─────┬────────────────────────┬────────────────────────────┬─────────────────────────┐ │ # │ Old command │ New command │ Status │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 21 │ twenty publish │ twenty app:publish │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 22 │ twenty publish --tag │ twenty app:publish --tag │ Deprecated → colon │ │ │ <tag> [appPath] │ <tag> [appPath] │ command │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 23 │ twenty deploy │ twenty app:publish │ Deprecated → colon │ │ │ [appPath] │ --private [appPath] │ command + --private │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 24 │ twenty install │ twenty app:install │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 25 │ twenty uninstall │ twenty app:uninstall │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 26 │ twenty uninstall -y │ twenty app:uninstall -y │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ └─────┴────────────────────────┴────────────────────────────┴─────────────────────────┘ Server commands ┌─────┬─────────────────────────┬─────────────────────────────┬──────────────────────┐ │ # │ Old command │ New command │ Status │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 27 │ twenty server start │ twenty docker:start │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 28 │ twenty server start -p │ twenty docker:start -p │ Deprecated → colon │ │ │ <port> │ <port> │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 29 │ twenty server start │ twenty docker:start --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 30 │ twenty server stop │ twenty docker:stop │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 31 │ twenty server stop │ twenty docker:stop --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 32 │ twenty server status │ twenty docker:status │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 33 │ twenty server status │ twenty docker:status --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 34 │ twenty server logs │ twenty docker:logs │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 35 │ twenty server logs -n │ twenty docker:logs -n │ Deprecated → colon │ │ │ <lines> │ <lines> │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 36 │ twenty server logs │ twenty docker:logs --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 37 │ twenty server reset │ twenty docker:reset │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 38 │ twenty server reset │ twenty docker:reset --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 39 │ twenty server upgrade │ twenty docker:upgrade │ Deprecated → colon │ │ │ [version] │ [version] │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 40 │ twenty server upgrade │ twenty docker:upgrade │ Deprecated → colon │ │ │ --test [version] │ --test [version] │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 41 │ twenty server │ twenty app:catalog-sync │ Deprecated → colon │ │ │ catalog-sync │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 42 │ twenty server │ twenty app:catalog-sync │ Deprecated → colon │ │ │ catalog-sync -r <name> │ -r <name> │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 43 │ twenty catalog-sync │ (removed) │ Removed (was already │ │ │ │ │ deprecated) │ └─────┴─────────────────────────┴─────────────────────────────┴──────────────────────┘ Remote commands ┌─────┬────────────────────────┬──────────────────────────┬──────────────────────────┐ │ # │ Old command │ New command │ Status │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 44 │ twenty remote add │ twenty remote:add │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 45 │ twenty remote add --as │ twenty remote:add --as │ Deprecated → colon │ │ │ <name> │ <name> │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 46 │ twenty remote add │ twenty remote:add │ Deprecated → colon │ │ │ --api-key <key> │ --api-key <key> │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 47 │ twenty remote add │ twenty remote:add │ Deprecated → colon │ │ │ --api-url <url> │ --api-url <url> │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 48 │ twenty remote add │ twenty remote:add │ Deprecated → colon │ │ │ --local │ --local │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 49 │ twenty remote add │ twenty remote:add --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 50 │ twenty remote list │ twenty remote:list │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 51 │ twenty remote switch │ twenty remote:use [name] │ Deprecated → colon │ │ │ [name] │ │ syntax + renamed │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 52 │ twenty remote status │ twenty remote:status │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 53 │ twenty remote remove │ twenty remote:remove │ Deprecated → colon │ │ │ <name> │ <name> │ syntax │ └─────┴────────────────────────┴──────────────────────────┴──────────────────────────┘ ``` --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> |
||
|
|
a2acf88a57 |
feat(website): per-PR preview deploys via Worker versions (#20762)
## Summary Adds review apps for the marketing site. Every PR that touches `packages/twenty-website/**` or `packages/twenty-shared/**` gets a per-version Worker preview URL, sticky-commented on the PR, auto-cleaned up when the PR closes. Same Cloudflare machinery skew protection rides on, just used for previews — no extra plan, no extra services. Cleaner than the GitHub-Actions-runner + Cloudflare-tunnel pattern: previews persist for the life of the version, accessible from anywhere, no warm-up. ## Files - **`.github/workflows/website-pr-preview.yaml`** — on PR open/sync/reopen: builds the Worker with a per-PR `DEPLOYMENT_ID`, runs `wrangler versions upload --tag pr-<N>` (no production traffic), sticky-comments the preview URL. Skipped on fork PRs because GitHub doesn't pass secrets to forks anyway. - **`.github/workflows/website-pr-preview-cleanup.yaml`** — on PR close: walks the Worker version list via the CF API, deletes anything tagged `pr-<N>` (with message-based fallback if the annotation key changes), updates the sticky comment. - **`open-next.config.ts`** — `maxNumberOfVersions: 10 → 50` to leave room for PR previews on top of skew protection's prod-version retention. ## How it looks on a PR The bot leaves a sticky comment like: > 🔍 **Website preview** is up at **https://abc12345-twenty-website-dev.twentyhq.workers.dev** > > | | | > |---|---| > | Version | `abc12345-...` | > | Commit | `<sha>` | > | Bindings | shared with the `dev` Worker (R2 cache + secrets) | > > Updates on every push. Auto-deleted when the PR closes. On close it becomes: > 🧹 Website preview for this PR was cleaned up after close. ## Twenty repo credentials already provisioned - `secret CLOUDFLARE_API_TOKEN` — same scoped token the `twenty-infra` workflow uses - `var CLOUDFLARE_ACCOUNT_ID` = `67b2bbe4381006564d2b0aa6ce6177be` - `var CF_PREVIEW_DOMAIN` = `twentyhq` (no `.workers.dev` suffix — OpenNext appends it; [opennextjs-cloudflare#811](https://github.com/opennextjs/opennextjs-cloudflare/issues/811)) ## Known limitations - **Shared dev bindings**: PR previews use the dev Worker's R2 bucket + secrets (Stripe test key, JWT private key). Fine for a read-mostly marketing site; if two simultaneous PRs ever fight over ISR cache state we can prefix R2 keys per-PR later. - **Fork PRs don't get previews**. GitHub Actions doesn't pass `secrets.*` to fork-PR runs (security), and the wrangler upload requires the CF token. To enable forks, would need to switch to `pull_request_target` and gate on a maintainer label — not done here because the security tradeoff isn't worth it for a marketing-site preview. - **Version cap**: 50 versions is the new ceiling, and `maxVersionAgeDays: 14` auto-prunes anything older. Cleanup-on-close should keep us well under in steady state. ## Test plan - [ ] CI on this PR triggers the preview workflow itself; check that the sticky comment appears with a working URL - [ ] Hit the URL, click around — should look like a fresh marketing-site build with this PR's changes - [ ] Close (don't merge) → cleanup workflow should run; sticky comment switches to the "cleaned up" message; the version is gone from `wrangler versions list --name twenty-website-dev` |
||
|
|
c002bc52bd |
fix(ci): repair preview-environment dispatch (use PAT, not GITHUB_TOKEN) (#20773)
## What One-line token swap on the same-repo dispatch step in [`preview-env-dispatch.yaml`](.github/workflows/preview-env-dispatch.yaml#L40): `secrets.GITHUB_TOKEN` → `secrets.CI_PRIVILEGED_DISPATCH_TOKEN`. ## Why Regression from [#20476](https://github.com/twentyhq/twenty/pull/20476) ("security: harden CI against supply-chain attacks"), merged 2026-05-12. That PR replaced ```yaml uses: peter-evans/repository-dispatch@v2 with: token: ${{ secrets.GITHUB_TOKEN }} ... ``` with a raw `gh api` call but kept `GITHUB_TOKEN`: ```yaml env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh api repos/"$REPOSITORY"/dispatches -f event_type=preview-environment ... ``` The auto-provisioned `GITHUB_TOKEN` can't fire `repository_dispatch` via `gh api` even when the workflow declares `permissions: contents: write`. The action used a different code path that worked; the CLI requires a token with `repo` scope. So every dispatch from this workflow has returned `403 Resource not accessible by integration` since that PR merged — except for runs the `author_association` / `preview-app` label gate skips entirely (which then show "success" because no jobs ran). Recent failed example: https://github.com/twentyhq/twenty/actions/runs/26162974597/job/76959379235?pr=20769 ## The fix `secrets.CI_PRIVILEGED_DISPATCH_TOKEN` already exists in repo secrets and is **already used** by the immediately-following cross-repo dispatch step in the same file. Using it for the same-repo dispatch too matches the surrounding code and is consistent with the original hardening intent (use a scoped PAT, not the auto-provisioned token). ## Test plan - [ ] Merge this PR - [ ] Next PR open / sync / reopen on a member's branch → check that `Preview Environment Dispatch` succeeds (no 403) - [ ] Confirm `Preview Environment Keep Alive` workflow gets triggered (the downstream effect of the dispatch) - [ ] Confirm the tunnel URL sticky comment lands on the PR Discovered while testing an unrelated PR ([#20762](https://github.com/twentyhq/twenty/pull/20762)). Independent fix. |
||
|
|
658bdf3e57 |
chore(website): rename twenty-website-new → twenty-website (#20745)
## Summary Follow-up to the Cloudflare/OpenNext migration (#20741). Now that the legacy `twenty-website` package was already removed in #20270, the `-new` suffix on the marketing site package is no longer meaningful. ## What changes - **Directory rename**: `git mv packages/twenty-website-new packages/twenty-website` (1213 files moved, no content change) - **Package + nx config**: `package.json` and `project.json` name fields updated, `sourceRoot` repointed - **Source refs**: `load-local-articles.ts` and `load-local-release-notes.ts` had a hardcoded `'twenty-website-new'` segment in their monorepo-root fallback path; `app/[locale]/releases/page.tsx` had display strings showing where to add content - **External refs**: root `package.json` workspaces, root `CLAUDE.md` / `README.md`, `twenty-sdk` + `create-twenty-app` READMEs, `.vscode/twenty.code-workspace`, `.cursor/rules/changelog-process.mdc`, Crowdin config + the three `website-i18n-*` CI workflows + `ci-website.yaml` - **Docker cleanup**: `packages/twenty-docker/twenty-website-new/Dockerfile` deleted; the two Makefile targets (`prod-website-new-build` / `prod-website-new-run`) that referenced it removed — EKS deploy was retired in the Cloudflare migration - **`yarn.lock`** regenerated against the new workspace path ## What's deliberately not in this PR The dev hostname `website-new.twenty-main.com` in `wrangler.jsonc` stays for now. Migrating it to `website.twenty-main.com` needs coordinated DNS deletion (current CNAME points at the legacy Docusaurus NLB and serves 503s) and removal of the matching legacy `website` Helm chart in `twenty-infra`. Flagged as a separate cleanup. Companion infra PR: https://github.com/twentyhq/twenty-infra/pull/682 (workflow paths + Terraform ECR + docs) ## Test plan - [x] `yarn install --immutable` resolves clean against the new path - [x] `npx nx typecheck twenty-website` passes - [x] `npx nx lint twenty-website` passes - [ ] CI on this PR confirms the same on a fresh checkout - [ ] After merge: trigger `Deploy Website` workflow against `environment=dev` to confirm the renamed working-directory deploys correctly |
||
|
|
d5ff9eb515 |
Create twenty app improvements (#20688)
create-twenty-app updates: - remove --example option - sync --once when scaffolding an applicaiton - rename --api-url option to --workspace-url - create a standalone page when scaffolding an app <img width="1494" height="765" alt="image" src="https://github.com/user-attachments/assets/0e35ed0c-b0aa-466c-9f56-7939294fd2cf" /> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> |
||
|
|
cf4b4455d3 |
fix(server): normalize composite defaultValues in manifest converter (unblock app re-install on 2.5-normalized workspaces) (#20615)
## Context The runtime create-field path and the v2.5 `NormalizeCompositeFieldDefaultsCommand` workspace upgrade both run composite `defaultValue`s through `nullifyEmptyCompositeDefaultValue`. The manifest install/sync path was the only write path that skipped it: [`fromFieldManifestToUniversalFlatFieldMetadata`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/application/application-manifest/converters/from-field-manifest-to-universal-flat-field-metadata.util.ts) passed `fieldManifest.defaultValue` through verbatim. For the SDK-emitted ACTOR system fields (`createdBy` / `updatedBy`), `twenty-sdk` ships `{ name: "''", source: "'MANUAL'" }`. After the runtime or the 2.5 normalize command stores them, the workspace row holds the canonical four-key form `{ context: null, name: null, source: "'MANUAL'", workspaceMemberId: null }`. The next install computes its TO map from the manifest, still gets the raw two-key shape, and diffs it against the normalized FROM. The dispatcher emits a `defaultValue` update on each system actor field; the flat-field-metadata validator rejects it with `FIELD_MUTATION_NOT_ALLOWED`, blocking every re-install of any application that defines a custom object on a v2.5-normalized workspace. ## Fix Normalize composite `defaultValue`s inside the converter, reusing the same `nullifyEmptyCompositeDefaultValue` helper the three other write paths already share: - [`get-default-flat-field-metadata-from-create-field-input.util.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util.ts) — `createOneObject` and `createOneField` GraphQL paths. - [`sanitize-raw-update-field-input.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/sanitize-raw-update-field-input.ts) — `updateOneField` GraphQL path. - [`2-5-workspace-command-1778000001000-normalize-composite-field-defaults.command.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/database/commands/upgrade-version-command/2-5/2-5-workspace-command-1778000001000-normalize-composite-field-defaults.command.ts) — the upgrade backfill that introduced the divergence. After the fix, the four write paths agree on the canonical shape, so re-installs are no-ops on system actor fields regardless of when the 2.5 normalize command ran. Non-composite types pass through unchanged. ## Test New spec `from-field-manifest-to-universal-flat-field-metadata.util.spec.ts` covers: - Empty-name actor defaults are normalized to the four-key canonical shape. - The converter is idempotent: feeding its own output back in produces the same result (so two consecutive syncs of the same manifest never emit a `defaultValue` update). - When the manifest omits `defaultValue`, the converter falls back to `generateDefaultValue` and normalizes the result. - Non-composite defaults pass through unchanged. ``` PASS src/engine/core-modules/application/application-manifest/converters/__tests__/from-field-manifest-to-universal-flat-field-metadata.util.spec.ts fromFieldManifestToUniversalFlatFieldMetadata composite defaultValue normalization ✓ normalizes empty-name actor defaults to the canonical four-key shape ✓ is idempotent: re-running the converter on its own output yields the same defaultValue ✓ falls back to the generated default and normalizes it when defaultValue is omitted ✓ leaves non-composite defaults untouched Tests: 4 passed ``` ## CI gap that let this through The integration suites covering manifest install (`appDevOnce` against the test workspace) never re-installed an existing app on a workspace whose composite fields had already been put through the 2.5 normalize command. They synced once, then ran assertions on the resulting state; the second sync that would have re-triggered the `defaultValue` diff was never exercised. If we want to catch this class of regression at the integration level too, we'd add a test that (1) syncs an app whose manifest includes an ACTOR system field with the raw SDK shape, (2) invokes `NormalizeCompositeFieldDefaultsCommand` directly on the test workspace, (3) re-syncs the same manifest, and (4) asserts no `FIELD_MUTATION_NOT_ALLOWED` errors. The unit-level idempotency check in this PR is the minimal version of that same coverage. Happy to ship that integration spec in a follow-up if it'd help. |
||
|
|
a754a95d38 | Regrant id token write to claude for oidc swap (#20564) | ||
|
|
0cc2194399 |
Simplify create-twenty-app command (#20512)
## Simplify `create-twenty-app` for zero-interaction use Makes `npx create-twenty-app@latest my-app` a fully non-interactive, single-command experience suitable for automated environments (Codex, Claude plugins). ### Changes - **Remove all interactive prompts** — app name, display name, description, and scaffold confirmation are now derived from CLI args with sensible defaults. `inquirer` dependency removed entirely. - **Replace OAuth with API key auth** — use the seeded dev API key (`DEV_API_KEY`) to authenticate against the Docker instance as `tim@apple.dev`, eliminating the browser-based OAuth flow. - **Docker-first with early validation** — check Docker is installed before scaffolding; if missing, print the install URL and exit. Detect alternative runtimes (Podman, nerdctl). - **Parallel image pull** — `docker pull` runs in the background during scaffold + dependency install, saving 10-30s on typical runs. - **Always pull latest image** — ensures the dev server is up-to-date on every run. - **Stop detecting port 3000** — only check port 2020 (Docker instance). - **Update CLI flags** — remove `--skip-local-instance` and `--yes`; add `--skip-docker`. - **Update CI workflows and docs** — align e2e workflows, package README, and template README/cd.yml with the new flow. |
||
|
|
565995e715 |
security: harden CI against supply-chain attacks (#20476)
- Pin all third-party actions to SHA - Gate claude.yml triggers to internal authors with Harden-Runner egress audit - Ignore fork-PR lifecycle scripts - Narrow cross-repo dispatch payloads - Add 7d npm release-age gate - Add CODEOWNERS on .github/** and .yarnrc.yml --------- Co-authored-by: prastoin <paul@twenty.com> |
||
|
|
b6b4824104 |
ci(preview-env): drop yarn -- separator so --light reaches the seed command (#20479)
## Summary Follow-up to #20464. That PR added `--light` to the preview env seed command but left the `--` between `yarn command:prod` and the script args. After yarn strips its own `--`, nest-commander still sees `argv: [..., '--', 'workspace:seed:dev', '--light']`. Commander.js treats `--` as the end-of-options marker, so `--light` is parsed as a positional arg and silently ignored — the seed runs in full mode (Apple + YCombinator + Empty3 + Empty4) and Empty4 still ends up as the default workspace. ## Evidence In the preview run on `f706cc052b` (which had #20464's `--light` flag), the seed step took only ~40s but the `GqlTypeGenerator` log emits four regenerations across two workspaces with custom objects: - 28 standard → 28 + 5 custom (`rocket, surveyResult, employmentHistory, petCareAgreement, pet`) — matches Apple - 28 standard → 28 + 1 custom (`surveyResult`) — matches YCombinator With `--light` actually applied, `getLightConfig` returns `{ objects: [], fields: [] }` so no custom objects should be generated. The working `twenty-app-dev` invocation in `packages/twenty-docker/twenty-app-dev/rootfs/etc/s6-overlay/scripts/init-db.sh:66` is `yarn command:prod workspace:seed:dev --light` — no `--`. Matching that fixes it. ## Test plan - [ ] Trigger the preview-app label on a PR, confirm only the Apple workspace is created and `tim@apple.dev` signs in there - [ ] Confirm the seed step still passes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |