Skip to content

Implement sync in dev mode#17405

Merged
martmull merged 24 commits intomainfrom
implement-sync-in-dev-mode
Jan 26, 2026
Merged

Implement sync in dev mode#17405
martmull merged 24 commits intomainfrom
implement-sync-in-dev-mode

Conversation

@martmull
Copy link
Copy Markdown
Contributor

@martmull martmull commented Jan 23, 2026

implement orchestrator to sync application in dev mode

Log example when starting dev mode, delete and add back functions

👩‍💻 Workspace - default
[init] 🚀 Starting Twenty Application Development Mode
[init] 📁 App Path: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto

[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/.gitignore
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/.nvmrc
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/.yarnrc.yml
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/README.md
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/eslint.config.mjs
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/package.json
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/tsconfig.json
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/yarn.lock
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/.yarn/install-state.gz
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/ooo.front-component.tsx
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/tata.object.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/application.config.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/default-function.role.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-2.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-3.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world.front-component.tsx
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/myObject.object.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/utils/toto.ts
[dev-mode] Building manifest...
[dev-mode] Successfully built manifest
[dev-mode] Syncing...
[dev-mode] ✓ Successfully built src/ooo.front-component.tsx
[dev-mode] Uploading .twenty/output/src/ooo.front-component.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world-2.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world-2.function.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world.front-component.tsx
[dev-mode] Uploading .twenty/output/src/app/hello-world.front-component.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world-3.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world-3.function.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world.function.mjs...
[dev-mode] Successfully uploaded .twenty/output/src/ooo.front-component.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world-3.function.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world.front-component.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world.function.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world-2.function.mjs
[dev-mode] ✓ Synced

[dev-mode] ✓ Successfully built src/app/hello-world-2.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world-2.function.mjs...
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world-2.function.mjs
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-2.function.ts
[dev-mode] Building manifest...
[dev-mode] Successfully built manifest
[dev-mode] Syncing...
[dev-mode] ✓ Synced
[dev-mode] Build failed:
[dev-mode]   Could not resolve "/Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world.function.ts"
[dev-mode]   Could not resolve "/Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-3.function.ts"
[dev-mode]   Could not resolve "/Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-2.function.ts"
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-2.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-3.function.ts
[dev-mode] Building manifest...
[dev-mode] ⚠ No functions defined
[dev-mode] Successfully built manifest
[dev-mode] Syncing...
  🗑️  Removed src/app/hello-world-2.function.mjs
  🗑️  Removed src/app/hello-world-3.function.mjs
  🗑️  Removed src/app/hello-world.function.mjs
[dev-mode] ✓ Synced
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-2.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-3.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world.function.ts
[dev-mode] Building manifest...
[dev-mode] Successfully built manifest
[dev-mode] Syncing...
[dev-mode] ✓ Successfully built src/app/hello-world-2.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world-2.function.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world-3.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world-3.function.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world.function.mjs...
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world.function.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world-2.function.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world-3.function.mjs
[dev-mode] ✓ Synced

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Jan 23, 2026

Greptile Overview

Greptile Summary

This PR implements automatic synchronization in development mode, allowing real-time manifest and file syncing with the server as developers make changes.

Key Changes:

  • Added yarnLock field to ApplicationManifest type to include dependency information in syncs
  • Integrated automatic application sync in app:dev command when manifest changes are detected
  • Added file upload functionality for built functions and front components in watch mode
  • Centralized yarn.lock reading in manifest build process instead of in sync command
  • Migrated test expected manifests from JSON to TypeScript files for better type safety

Issues Found:

  • Missing error handling for yarn.lock file read operation - will throw if file doesn't exist
  • No debouncing for rapid manifest changes, which could trigger multiple simultaneous sync operations

Confidence Score: 3/5

  • This PR has one critical issue that needs addressing before merge
  • The missing error handling for yarn.lock file reading is a critical issue that will cause the manifest build to fail if the file doesn't exist. While the implementation is otherwise solid, this logic error needs to be fixed to prevent runtime failures in projects without a yarn.lock file.
  • Pay close attention to packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-build.ts - the yarn.lock reading needs error handling

Important Files Changed

Filename Overview
packages/twenty-sdk/src/cli/commands/app/app-dev.ts Added sync functionality to dev mode - syncs application manifest on changes and uploads built files
packages/twenty-sdk/src/cli/commands/app/app-sync.ts Simplified by removing yarn.lock reading logic (now handled in manifest build)
packages/twenty-sdk/src/cli/utilities/api/api-service.ts Updated syncApplication to accept manifest parameter and extract yarnLock from it
packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-build.ts Added yarn.lock reading to manifest build - reads file synchronously without error handling
packages/twenty-shared/src/application/applicationManifestType.ts Added yarnLock field to ApplicationManifest type

Sequence Diagram

sequenceDiagram
    participant Dev as Developer
    participant AppDev as AppDevCommand
    participant ManifestWatcher as ManifestWatcher
    participant ManifestBuild as ManifestBuild
    participant FunctionsWatcher as FunctionsWatcher
    participant FrontComponentsWatcher as FrontComponentsWatcher
    participant FileUploader as FileUploader
    participant ApiService as ApiService
    participant Server as Twenty Server

    Dev->>AppDev: Execute app:dev command
    AppDev->>ManifestBuild: runManifestBuild(appPath)
    ManifestBuild->>ManifestBuild: Read package.json
    ManifestBuild->>ManifestBuild: Read yarn.lock file
    ManifestBuild->>ManifestBuild: Build all entities
    ManifestBuild-->>AppDev: Return manifest + file paths
    
    AppDev->>AppDev: Initialize FileUploader
    AppDev->>ManifestWatcher: Start watching manifest changes
    AppDev->>FunctionsWatcher: Start watching function files
    AppDev->>FrontComponentsWatcher: Start watching front component files
    
    Note over Dev,Server: Dev mode active - watching for changes
    
    ManifestWatcher->>ManifestBuild: File change detected
    ManifestBuild->>ManifestBuild: Rebuild manifest with yarn.lock
    ManifestBuild-->>ManifestWatcher: Return updated manifest
    ManifestWatcher->>AppDev: onBuildSuccess(manifest)
    AppDev->>ApiService: syncApplication(manifest)
    ApiService->>Server: POST /metadata (mutation SyncApplication)
    Server-->>ApiService: Sync result
    ApiService-->>AppDev: Success/Error response
    
    FunctionsWatcher->>FunctionsWatcher: Function file changed
    FunctionsWatcher->>AppDev: onFileBuilt(builtPath, checksum)
    AppDev->>AppDev: updateFileStatus
    AppDev->>FileUploader: uploadFile(builtPath, FileFolder.BuiltFunction)
    FileUploader->>Server: Upload function file
    
    FrontComponentsWatcher->>FrontComponentsWatcher: Component file changed
    FrontComponentsWatcher->>AppDev: onFileBuilt(builtPath, checksum)
    AppDev->>AppDev: updateFileStatus
    AppDev->>FileUploader: uploadFile(builtPath, FileFolder.BuiltFrontComponent)
    FileUploader->>Server: Upload component file
Loading

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +149 to +152
const yarnLock = await readFile(
await findPathFile(appPath, 'yarn.lock'),
'utf8',
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling for yarn.lock file read. If yarn.lock doesn't exist, findPathFile will throw an error. Consider handling this gracefully by defaulting to an empty string when the file is missing.

Suggested change
const yarnLock = await readFile(
await findPathFile(appPath, 'yarn.lock'),
'utf8',
);
const yarnLockPath = await findPathFile(appPath, 'yarn.lock').catch(
() => null,
);
const yarnLock = yarnLockPath
? await readFile(yarnLockPath, 'utf8')
: '';
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-build.ts
Line: 149:152

Comment:
Missing error handling for yarn.lock file read. If `yarn.lock` doesn't exist, `findPathFile` will throw an error. Consider handling this gracefully by defaulting to an empty string when the file is missing.

```suggestion
    const yarnLockPath = await findPathFile(appPath, 'yarn.lock').catch(
      () => null,
    );
    const yarnLock = yarnLockPath
      ? await readFile(yarnLockPath, 'utf8')
      : '';
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +165 to +166
private async syncApplication(manifest: ApplicationManifest): Promise<void> {
initLogger.log('Sync application');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding context to the log message to be more informative, e.g., "Syncing application manifest..."

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/twenty-sdk/src/cli/commands/app/app-dev.ts
Line: 165:166

Comment:
Consider adding context to the log message to be more informative, e.g., "Syncing application manifest..."

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +155 to +157
if (result.manifest) {
await this.syncApplication(result.manifest);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding debouncing if rapid file changes could trigger multiple sync operations simultaneously.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/twenty-sdk/src/cli/commands/app/app-dev.ts
Line: 155:157

Comment:
Consider adding debouncing if rapid file changes could trigger multiple sync operations simultaneously.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 14 files

@martmull martmull force-pushed the implement-sync-in-dev-mode branch from e1c82f2 to bbce1b8 Compare January 23, 2026 16:39
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 7 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/twenty-sdk/src/cli/utilities/dev/dev-mode-orchestrator.ts">

<violation number="1" location="packages/twenty-sdk/src/cli/utilities/dev/dev-mode-orchestrator.ts:185">
P2: Changes detected during an in-flight sync can be dropped because performSync returns without scheduling a follow-up sync. Schedule another sync instead of returning silently so updates during a sync are eventually applied.</violation>
</file>

<file name="packages/twenty-sdk/src/cli/commands/app/app-dev.ts">

<violation number="1" location="packages/twenty-sdk/src/cli/commands/app/app-dev.ts:73">
P2: Handle errors from startFileWatchers to avoid unhandled promise rejections when watcher startup fails.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


export const EXPECTED_MANIFEST: ApplicationManifest = {
sources: {},
yarnLock: '',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid storing files in JSON, this doesn't scale well (same for sources)
I would upload it too (to me it's actully part of the sourceCode of the app but as we will also need it for the functions layer, we can maybe store it somewhere else too.

(by the way, whenever we update the yarn.lock, we should rebuild the functionLayer, to me it's part of the application syncProcess and should generate a migrtion)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, i will improve behavior in another PR. I will use package.json and yarn.lock from tarball sources instead of core.serverlessFunctionLayer columns values

@martmull martmull force-pushed the implement-sync-in-dev-mode branch 3 times, most recently from a437c3b to e36daa5 Compare January 26, 2026 13:11
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 15 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__e2e__/applications-install-delete-reinstall.e2e-spec.ts">

<violation number="1" location="packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__e2e__/applications-install-delete-reinstall.e2e-spec.ts:32">
P2: The manifest is written to `.twenty/output/manifest.json`, but the test now checks for `manifest.json` at the app root. Update the assertion to point at the output directory so the test validates the generated manifest.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@martmull martmull force-pushed the implement-sync-in-dev-mode branch from 4ef842e to a314557 Compare January 26, 2026 13:47
@charlesBochet
Copy link
Copy Markdown
Member

Tested it locally, awesome!

Feedbacks from usage on my own app (can be treated in another PR)

  • when the local instance is not up, it's throwing big (hard to read errors). We should improve error readability + maybe check that we can reach out the instance before starting app:dev?

Copy link
Copy Markdown
Member

@charlesBochet charlesBochet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, awesome, I've left a few comments but non blocking
We just need to fix tests

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jan 26, 2026

🚀 Preview Environment Ready!

Your preview environment is available at: http://bore.pub:48094

This environment will automatically shut down when the PR is closed or after 5 hours.

@martmull martmull force-pushed the implement-sync-in-dev-mode branch from b4e3d5f to eaec100 Compare January 26, 2026 18:27
@martmull martmull force-pushed the implement-sync-in-dev-mode branch from eaec100 to c7b400e Compare January 26, 2026 19:05
@martmull martmull added this pull request to the merge queue Jan 26, 2026
Merged via the queue into main with commit 41d470e Jan 26, 2026
79 checks passed
@martmull martmull deleted the implement-sync-in-dev-mode branch January 26, 2026 19:44
@twenty-eng-sync
Copy link
Copy Markdown

Hey @martmull! After you've done the QA of your Pull Request, you can mark it as done here. Thank you!

1 similar comment
@twenty-eng-sync
Copy link
Copy Markdown

Hey @martmull! After you've done the QA of your Pull Request, you can mark it as done here. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants