Skip to content

Conversation

@evereq
Copy link
Member

@evereq evereq commented Jan 8, 2026

PR

Please note: we will close your PR without comment if you do not check the boxes above and provide ALL requested information.



Summary by cubic

Integrates a Plugin Marketplace across Agent, Desktop, and Desktop Timer, and adds a theme-aware custom tray icon with live time display in the Desktop Timer. Updates CI/CD to Node v24 with consistent job timeouts and refactors packaging to support arch-specific update channels.

  • New Features

    • Plugin Marketplace window and route with AuthConnectionGuard; tray menu entry to open it.
    • Desktop Timer tray icon: custom canvas rendering, light/dark theme support, IPC updates, default icon asset.
    • Icon generator supports tray icon via GAUZY_DESKTOP_TRAY_ICON.
    • Packaging refactor: BasePackager with per-arch publish channel for auto-updates.
    • SECURITY.md: CVE clarification for demo environment.
  • CI/Build

    • CircleCI: Node orb v7.2.1, Node v24, postinstall.manual, larger resource classes, improved caches, updated SonarScanner.
    • GitHub Actions: add timeout-minutes across release, deploy, test, and analysis workflows.
    • Test configs: remove deprecated tsConfig entries in Nx Jest/Cypress projects.
    • Dependencies bumped: NestJS 11.1.10, @ng-select/ng-select 14.9.0, express 5.2.1, MCP SDK 1.25.2, Angular peer deps.

Written for commit 1305983. Summary will update on new commits.

evereq and others added 30 commits December 23, 2025 16:32
* chore: update yarn.lock baseline

* chore: upgrade @nestjs and related packages from v11.1.0 to v11.1.10
* feat(window): add Plugin Marketplace window and wire it in desktop-window

* feat(ui/plugins): add Plugin Marketplace UI (list, detail, upload, filters, layout, styles)

* refactor(settings): wire plugin routes and access guard; update settings module

* refactor(desktop): menu/tray entries to open Plugin Marketplace window

* refactor(core): extend window manager interface to support plugin windows

* chore(timer): update routing/module and bootstrap for plugin window integration

* feat: export new components and modules

This commit adds exports for several new components and modules from the desktop-ui-lib. This includes components related to login, agent dashboard, integrations, language, recap, settings, and time tracker. These exports make these components and modules available for use in other parts of the application.

* feat(plugins): add plugin route and tray menu item

Adds a new route for plugins and integrates a new menu item into the tray icon's context menu. This enables users to access the plugin marketplace directly from the system tray.
The `app-routing.module.ts` now includes a 'plugins' path with a guard and lazy loading for plugin-related components and routes. The `app.module.ts` imports the `PluginsModule`.
The `tray.ts` file is updated to include a new "Plugins" menu item in the tray icon. Clicking this item will open the `PluginMarketplaceWindow` if it's not already open, or focus it if it is. This feature enhances the agent's extensibility and user experience by providing easy access to plugins.

* feat(plugins): implement plugin marketplace and routing

Integrates the plugin marketplace into the application and sets up the necessary routing for plugin management. This includes adding the `PluginsModule` to both desktop and server applications, and configuring the `plugins` route with `AuthConnectionGuard` to ensure authenticated access.
The plugin marketplace window is now created and loaded in both desktop and server entry points. This feature allows for dynamic loading and management of plugins within the application.

* fix(package): add missing newline at end of package.json

* fix(plugins): ensure plugin window is retrieved after creation

When creating a new plugin marketplace window, the code immediately tried to show it without re-retrieving the window instance from the `WindowManager`. This commit ensures that the `window` variable is updated after the new window is created, so that `window.show()` is called on the correct instance.
Additionally, removed an unnecessary `toggleDevTools()` call from the `PluginMarketplaceWindow` constructor.
Also updated the `desktop-ui-lib` to correctly bind the `routerLink` directive and added `ChangeDetectionStrategy.OnPush` to `PluginLayoutComponent` for performance.

* fix(tray): use correct ui path for plugin marketplace window

When opening the plugin marketplace window, the incorrect path was being used. This commit updates the path to `appWindow.getUiPath('plugins')` to ensure the window loads correctly.

* fix(plugin-layout): remove unnecessary change detection strategy

The `ChangeDetectionStrategy.OnPush` was implicitly handled by Angular's default behavior when not explicitly set. Removing it simplifies the component definition without altering its functionality or performance.
* feat(employee): change User-Employee relation from OneToOne to ManyToOne

This allows one User to have multiple Employee records across different
organizations within the same tenant.

Fixes #8465

* feat(migration): add PostgreSQL migration for User-Employee relation change

Removes UNIQUE constraint on employee.userId to allow multiple employees
per user across organizations.

* feat(database): add MySQL migration to remove UNIQUE constraint on employee.userId

Adds MySQL Up/Down migration queries to support multi-employee per user
across organizations.

- MySQL Up: Drops FK, drops UNIQUE index, re-adds FK
- MySQL Down: Drops FK, creates UNIQUE index, re-adds FK

Related to #8465

* fix(employee): add organizationId context to findOneByUserId and findEmployeeIdByUserId

- Add RequestContext.currentOrganizationId() to retrieve organization from headers
- Update findEmployeeIdByUserId to accept optional organizationId parameter
- Update findOneByUserId to include tenantId and organizationId in where clause
- Ensures correct employee is found when user has multiple employees across organizations

Related to #8465

* fix(employee): prevent duplicate user creation and fix organization switcher for employees

- EmployeeCreateHandler: Check if user with email exists in tenant before creating new user
- header.component: Show organization selector if user has more than 1 organization
- organization.component: Only request featureOrganizations relations if user has ALL_ORG_VIEW permission

Related to #8465

* fix(auth): support multi-organization employee context switching

- Modified jwt.strategy.ts to verify JWT employeeId belongs to user, then
  dynamically get the employee for the current organization context
- Created OrganizationContextService to automatically refresh user data
  (including correct employee) when selectedOrganization changes
- Integrated OrganizationContextService initialization in AppInitService
- This ensures store.user.employee always reflects the current organization

Fixes #8465

* feat(auth): add switch-organization API endpoint

- Add SwitchOrganizationDTO for the switch organization request
- Add AuthService.switchOrganization() method to generate new JWT
  with correct employeeId for target organization
- Add POST /auth/switch-organization endpoint in AuthController
- Modify EmployeeService.findOneByUserId() to accept optional organizationId
- Modify AuthService.getJwtAccessToken() to accept optional organizationId

This allows users with employees in multiple organizations to switch
context and receive a new JWT with the correct employeeId.

Relates to #8465

* refactor(auth): simplify jwt.strategy.ts validation

- Verify employeeId from JWT belongs to the user (security check)
- Assign employeeId directly from JWT (no dynamic lookup needed)
- JWT now always contains correct employeeId for current organization
  (regenerated via /auth/switch-organization when user switches)

Relates to #8465

* feat(ui): integrate organization switch with new JWT regeneration

- Add AuthService.switchOrganization() to call backend API
- Rewrite OrganizationContextService to use explicit switch API
  instead of automatic listener-based refresh
- Modify OrganizationSelectorComponent.selectOrganization() to call
  OrganizationContextService.switchOrganization() and update tokens

When user switches organization, the frontend now:
1. Calls POST /auth/switch-organization
2. Receives new JWT with correct employeeId
3. Updates store with new tokens and user data
4. Updates selected organization in URL

Fixes #8465

* fix(employee): wrap findOneByWhereOptions in try-catch to handle NotFoundException

findOneByWhereOptions throws NotFoundException when no record is found,
but the code assumed it returns null. This caused an exception instead
of proceeding to create a new user when the user doesn't exist.

* refactor(ui-core): remove no-op OrganizationContextService.initialize() call

The initialize() method is a no-op for backward compatibility, but the
comment claimed it would refresh user.employee when organization changes.
Removed both the misleading comment and the unnecessary method call.

* fix(auth): add block scope to switch case clauses to prevent variable leaking

Switch statements in JS/TS share scope across case clauses, which can
cause variable declarations to leak or conflict. Wrapped MikroORM and
TypeORM case bodies in their own blocks ({}) so declarations are
lexically scoped to each case.

* Update packages/core/src/lib/auth/auth.service.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix migration

* feat(auth): add organization context to JWT tokens and secure organization switching

- Add CHANGE_SELECTED_ORGANIZATION permission to EMPLOYEE role
- Add PermissionGuard to /switch-organization endpoint
- Add organizationId to JWT access token payload
- Add organizationId to JWT refresh token payload
- Update getAccessTokenFromRefreshToken to maintain organization context
- Secure RequestContext.currentOrganizationId() to read from JWT instead of headers

BREAKING CHANGE: JWT tokens now include organizationId field. Clients should handle the new token structure.

* fix(ui): restore CHANGE_SELECTED_ORGANIZATION permission check for organization selector

Re-add permission verification that was removed - users without
CHANGE_SELECTED_ORGANIZATION permission should not see the organization
selector in the header.

* fix(migration): remove UNIQUE constraint on userId in SQLite UP migration

Remove CONSTRAINT REL_f4b0d329c4a3cf79ffe9d56504 UNIQUE (userId) from all
CREATE TABLE temporary_employee statements in sqliteUpQueryRunner to allow
many-to-one relationship (multiple employees can reference the same user).

The DOWN migration retains the UNIQUE constraint to restore the original
one-to-one relationship when reverting.

* fix(context): merge duplicate currentOrganizationId methods with proper fallback

Consolidate two currentOrganizationId() methods into one with priority:
1. JWT token organizationId (most secure)
2. User's employee organizationId (fallback for old tokens)
3. Request header organization-id (legacy backward compatibility)

This ensures existing functionality continues to work while preferring
the secure JWT-based organization context when available.

* fix(auth): inject organizationId from JWT into user with fallback

Make organizationId follow the same pattern as employeeId:
- jwt.strategy.ts: inject organizationId from JWT into user.lastOrganizationId
- request-context.ts: currentOrganizationId() reads from user.lastOrganizationId
  with fallback to user.employee.organizationId and header for backward compatibility

This ensures consistency across all context methods while maintaining
backward compatibility with old tokens.

* fix(auth): validate organization access in JWT strategy

- Add UserOrganizationService to validate user has access to organization
- Remove unvalidated header fallback from currentOrganizationId()
- organizationId is now only accepted from validated JWT tokens

* fix(employee): catch specific NotFoundException and validate input

- Catch only NotFoundException instead of all errors
- Add validation for input.user.email before accessing it

* fix(ui): add await for async selectOrganization calls

- Make updateOrganization, deleteOrganization, selectOrganizationById async
- Properly await selectOrganization to prevent race conditions

* fix(ui): add @deprecated to initialize() method

- Mark initialize() as deprecated with JSDoc
- Clean up comments in applyOrganizationData()

* docs(auth): clarify refresh token organization behavior

- Add note explaining refresh token is organization-specific
- Document that /auth/switch-organization should be used to change org

* refactor(ui): use inject() function instead of constructor injection

- Replace constructor parameter injection with inject() function
- Follow Angular modern DI pattern

* fix(auth): include organizationId in refresh token

- Pass organizationId to getJwtRefreshToken in login, signinWorkspaceByToken, and switchWorkspace
- Ensures refresh token contains same organization context as access token

* fix(auth): add cross-validation between employeeId and organizationId in JWT

- Validate that employee.organizationId matches the claimed organizationId
- Prevents JWT token manipulation attacks

* fix(employee): use BadRequestException and check for existing employee

- Use BadRequestException instead of generic Error for proper HTTP 400
- Check if employee already exists for user+organization to prevent duplicates

* fix(ui): validate response fields before applying to store

- Check token and user exist before updating store
- Return false and show error if validation fails

* fix(auth): update user.lastOrganizationId in memory after DB update

- Ensures returned user object has fresh lastOrganizationId value

* fix(employee): load role relation when finding existing user

- Use findOneByOptions with relations: { role: true }
- Fixes 'Cannot read properties of undefined (reading name)' error
- addUserToOrganization requires user.role.name for SUPER_ADMIN check

---------

Co-authored-by: Ruslan Konviser <[email protected]>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* docs: add CVE Clarifications

* Update SECURITY.md

* fix: agent build release path

* Merge pull request #9303 from ever-co/feat/shared-entity-module-feature

[Feat] Shared entity module feature

* Fix/user employee duplicate issue 8465 (#9272)

* feat(employee): change User-Employee relation from OneToOne to ManyToOne

This allows one User to have multiple Employee records across different
organizations within the same tenant.

Fixes #8465

* feat(migration): add PostgreSQL migration for User-Employee relation change

Removes UNIQUE constraint on employee.userId to allow multiple employees
per user across organizations.

* feat(database): add MySQL migration to remove UNIQUE constraint on employee.userId

Adds MySQL Up/Down migration queries to support multi-employee per user
across organizations.

- MySQL Up: Drops FK, drops UNIQUE index, re-adds FK
- MySQL Down: Drops FK, creates UNIQUE index, re-adds FK

Related to #8465

* fix(employee): add organizationId context to findOneByUserId and findEmployeeIdByUserId

- Add RequestContext.currentOrganizationId() to retrieve organization from headers
- Update findEmployeeIdByUserId to accept optional organizationId parameter
- Update findOneByUserId to include tenantId and organizationId in where clause
- Ensures correct employee is found when user has multiple employees across organizations

Related to #8465

* fix(employee): prevent duplicate user creation and fix organization switcher for employees

- EmployeeCreateHandler: Check if user with email exists in tenant before creating new user
- header.component: Show organization selector if user has more than 1 organization
- organization.component: Only request featureOrganizations relations if user has ALL_ORG_VIEW permission

Related to #8465

* fix(auth): support multi-organization employee context switching

- Modified jwt.strategy.ts to verify JWT employeeId belongs to user, then
  dynamically get the employee for the current organization context
- Created OrganizationContextService to automatically refresh user data
  (including correct employee) when selectedOrganization changes
- Integrated OrganizationContextService initialization in AppInitService
- This ensures store.user.employee always reflects the current organization

Fixes #8465

* feat(auth): add switch-organization API endpoint

- Add SwitchOrganizationDTO for the switch organization request
- Add AuthService.switchOrganization() method to generate new JWT
  with correct employeeId for target organization
- Add POST /auth/switch-organization endpoint in AuthController
- Modify EmployeeService.findOneByUserId() to accept optional organizationId
- Modify AuthService.getJwtAccessToken() to accept optional organizationId

This allows users with employees in multiple organizations to switch
context and receive a new JWT with the correct employeeId.

Relates to #8465

* refactor(auth): simplify jwt.strategy.ts validation

- Verify employeeId from JWT belongs to the user (security check)
- Assign employeeId directly from JWT (no dynamic lookup needed)
- JWT now always contains correct employeeId for current organization
  (regenerated via /auth/switch-organization when user switches)

Relates to #8465

* feat(ui): integrate organization switch with new JWT regeneration

- Add AuthService.switchOrganization() to call backend API
- Rewrite OrganizationContextService to use explicit switch API
  instead of automatic listener-based refresh
- Modify OrganizationSelectorComponent.selectOrganization() to call
  OrganizationContextService.switchOrganization() and update tokens

When user switches organization, the frontend now:
1. Calls POST /auth/switch-organization
2. Receives new JWT with correct employeeId
3. Updates store with new tokens and user data
4. Updates selected organization in URL

Fixes #8465

* fix(employee): wrap findOneByWhereOptions in try-catch to handle NotFoundException

findOneByWhereOptions throws NotFoundException when no record is found,
but the code assumed it returns null. This caused an exception instead
of proceeding to create a new user when the user doesn't exist.

* refactor(ui-core): remove no-op OrganizationContextService.initialize() call

The initialize() method is a no-op for backward compatibility, but the
comment claimed it would refresh user.employee when organization changes.
Removed both the misleading comment and the unnecessary method call.

* fix(auth): add block scope to switch case clauses to prevent variable leaking

Switch statements in JS/TS share scope across case clauses, which can
cause variable declarations to leak or conflict. Wrapped MikroORM and
TypeORM case bodies in their own blocks ({}) so declarations are
lexically scoped to each case.

* Update packages/core/src/lib/auth/auth.service.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix migration

* feat(auth): add organization context to JWT tokens and secure organization switching

- Add CHANGE_SELECTED_ORGANIZATION permission to EMPLOYEE role
- Add PermissionGuard to /switch-organization endpoint
- Add organizationId to JWT access token payload
- Add organizationId to JWT refresh token payload
- Update getAccessTokenFromRefreshToken to maintain organization context
- Secure RequestContext.currentOrganizationId() to read from JWT instead of headers

BREAKING CHANGE: JWT tokens now include organizationId field. Clients should handle the new token structure.

* fix(ui): restore CHANGE_SELECTED_ORGANIZATION permission check for organization selector

Re-add permission verification that was removed - users without
CHANGE_SELECTED_ORGANIZATION permission should not see the organization
selector in the header.

* fix(migration): remove UNIQUE constraint on userId in SQLite UP migration

Remove CONSTRAINT REL_f4b0d329c4a3cf79ffe9d56504 UNIQUE (userId) from all
CREATE TABLE temporary_employee statements in sqliteUpQueryRunner to allow
many-to-one relationship (multiple employees can reference the same user).

The DOWN migration retains the UNIQUE constraint to restore the original
one-to-one relationship when reverting.

* fix(context): merge duplicate currentOrganizationId methods with proper fallback

Consolidate two currentOrganizationId() methods into one with priority:
1. JWT token organizationId (most secure)
2. User's employee organizationId (fallback for old tokens)
3. Request header organization-id (legacy backward compatibility)

This ensures existing functionality continues to work while preferring
the secure JWT-based organization context when available.

* fix(auth): inject organizationId from JWT into user with fallback

Make organizationId follow the same pattern as employeeId:
- jwt.strategy.ts: inject organizationId from JWT into user.lastOrganizationId
- request-context.ts: currentOrganizationId() reads from user.lastOrganizationId
  with fallback to user.employee.organizationId and header for backward compatibility

This ensures consistency across all context methods while maintaining
backward compatibility with old tokens.

* fix(auth): validate organization access in JWT strategy

- Add UserOrganizationService to validate user has access to organization
- Remove unvalidated header fallback from currentOrganizationId()
- organizationId is now only accepted from validated JWT tokens

* fix(employee): catch specific NotFoundException and validate input

- Catch only NotFoundException instead of all errors
- Add validation for input.user.email before accessing it

* fix(ui): add await for async selectOrganization calls

- Make updateOrganization, deleteOrganization, selectOrganizationById async
- Properly await selectOrganization to prevent race conditions

* fix(ui): add @deprecated to initialize() method

- Mark initialize() as deprecated with JSDoc
- Clean up comments in applyOrganizationData()

* docs(auth): clarify refresh token organization behavior

- Add note explaining refresh token is organization-specific
- Document that /auth/switch-organization should be used to change org

* refactor(ui): use inject() function instead of constructor injection

- Replace constructor parameter injection with inject() function
- Follow Angular modern DI pattern

* fix(auth): include organizationId in refresh token

- Pass organizationId to getJwtRefreshToken in login, signinWorkspaceByToken, and switchWorkspace
- Ensures refresh token contains same organization context as access token

* fix(auth): add cross-validation between employeeId and organizationId in JWT

- Validate that employee.organizationId matches the claimed organizationId
- Prevents JWT token manipulation attacks

* fix(employee): use BadRequestException and check for existing employee

- Use BadRequestException instead of generic Error for proper HTTP 400
- Check if employee already exists for user+organization to prevent duplicates

* fix(ui): validate response fields before applying to store

- Check token and user exist before updating store
- Return false and show error if validation fails

* fix(auth): update user.lastOrganizationId in memory after DB update

- Ensures returned user object has fresh lastOrganizationId value

* fix(employee): load role relation when finding existing user

- Use findOneByOptions with relations: { role: true }
- Fixes 'Cannot read properties of undefined (reading name)' error
- addUserToOrganization requires user.role.name for SUPER_ADMIN check

---------

Co-authored-by: Ruslan Konviser <[email protected]>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: syns2191 <[email protected]>
Co-authored-by: Gloire Mutaliko (Salva) <[email protected]>
Co-authored-by: samuel mbabhazi <[email protected]>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
fix: table name plugins conflict in desktop with integrated and sqlit…
* feat: desktop timer enhance tray ui with custom icon

* fix: handle theme color change

* fix: handled possible duplicated listener

* fix: add event update-tray-icon in remove listener

* fix: remove log
Adds a new menu item for advanced settings to the settings component. This allows users to access advanced configuration options that were previously not directly available in the UI.
Fix(settings): Add advanced settings menu item
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
rahul-rocket and others added 12 commits January 6, 2026 18:13
chore(deps): bump nx from 20.8.0 to 21.1.0
…ypto

Fix/8504 replace bcrypt with crypto
fix(core): export PasswordHashModule and PasswordHashService
* feat(plugins): implement upload selection modal and intent handling

Introduces a new upload selection modal that allows users to choose between installing a plugin locally or publishing it to the marketplace.
This change includes:
- A new `UploadSelectionComponent` with its associated HTML, SCSS, and TypeScript files.
- New actions (`PluginUploadIntentActions`) and effects (`PluginUploadIntentEffects`) to manage the upload intent flow.
- Updates to `PluginMarketplaceComponent` to trigger the upload selection.
- New Akita store (`PluginUploadIntentStore`) and query (`PluginUploadIntentQuery`) to manage the upload intent state.
- Internationalization updates for the new upload selection options.
This refactors the previous direct "Upload" action in the plugin marketplace to provide a more guided user experience. The "Add Plugin" button's functionality is now integrated within the "Install Locally" flow of the new upload selection modal.

* feat(plugins): redesign add plugin modal

Refactors the add plugin modal to improve user experience and UI clarity.
The changes include:
- A new card-based design for installation options (local, CDN, NPM) with clear descriptions and icons.
- Improved form structure for CDN and NPM installations, including better input fields and error handling.
- Enhanced accessibility features such as ARIA labels and focus management.
- A new signal-based approach for managing component state.
- Refined styling for better responsiveness and visual appeal.
- Added a subtitle to the plugin modal header.

* feat(plugins): enhance plugin list and marketplace detail components with improved state handling and accessibility features

* feat(plugins): adjust nb-toggle label margin for improved layout consistency

* fix(i18n): remove unused upload translation

The "UPLOAD" translation key was no longer being used in the UI. Removing it helps to keep the i18n files clean and maintainable.

* fix(desktop-ui-lib): enable keyboard navigation for upload selection

Add keyboard event listeners for 'enter' and 'space' keys to the upload selection cards. This allows users to select an installation option using their keyboard, improving accessibility and usability.

* feat(plugins): translate add plugin options and aria-labels

Translate the descriptive text and ARIA labels for the "Install from Computer", "Install from CDN", and "Install from NPM" options within the add plugin component.
This change ensures that these options are properly localized and accessible to users who rely on translated interfaces. The `en.json` file has been updated with new translation keys for these strings.

* fix(add-plugin): correct conditional rendering logic

Update the template to use `@else if` for conditional rendering of plugin installation forms. This ensures that only one form is displayed at a time based on the context (CDN or NPM), preventing potential rendering issues and improving user experience.

* fix(desktop-ui-lib): refactor plugin settings styles to use theme variables

This commit refactors the SCSS styles for the plugin settings component in the desktop UI library. Instead of using hardcoded color and shadow values, it now utilizes theme variables. This change improves consistency across the application and makes it easier to manage the visual theme.
The specific changes include:
- Replacing hardcoded rgba shadows with `var(--gauzy-shadow)`.
- Replacing hardcoded rgba borders with `var(--border-basic-color-3)`.
- Replacing hardcoded rgba background colors with theme-specific variables like `var(--background-basic-color-2)`, `var(--color-primary-100)`, `var(--color-success-100)`, and `var(--color-danger-100)`.
- Replacing hardcoded focus outlines with `var(--color-primary-focus)`.
- Replacing hardcoded color values for icons and text with theme variables.
- Replacing hardcoded input border colors on hover and focus with theme variables.
- Replacing hardcoded background for the plugin details section with `var(--gauzy-card-2)`.

* fix(add-plugin): initialize npmModel with default structure

The `npmModel` was not being initialized with its default structure when the `reset` method was called. This commit ensures that `npmModel` is properly reset to its expected shape, preventing potential issues with form handling or state management.

* refactor(plugin-list): improve readability of template variable declarations

Break down the long `@let` declaration into multiple lines for better readability.
Add comments to explain the purpose of each state variable.

* fix(plugin-list): use theme variable for hover shadow

Replaces the hardcoded box-shadow value with the `--gauzy-shadow` CSS variable for the plugin list item hover effect. This ensures consistency with the application's theme and allows for easier global shadow management.

* fix(desktop-ui-lib): improve danger button styling and use inject

This commit refactors the `.danger` CSS class to use CSS variables for more maintainable and themeable background colors. It also updates the `PluginUploadIntentEffects` to use the `inject` function for dependency injection, which is a more modern Angular practice.

* chore: remove unused animation keyframes

The `@keyframes pulse` was defined but not used anywhere in the
component's stylesheet. This commit removes the unused animation
definition to clean up the code and reduce file size.

* fix(plugin-upload-intent): handle empty or null intents correctly

The previous implementation incorrectly returned an empty array or a single action without proper handling of null or undefined upload intents. This change ensures that the observable correctly emits `EMPTY` when no valid intent is provided, and uses `of()` for dispatching single actions to avoid unexpected behavior.

* fix(plugin-upload-intent): allow null for intent

The `intent` property in `PluginUploadIntentQuery` and `IPluginUploadIntentState` was previously typed as `UploadIntent`, implying it must always have a value. However, the `setIntent` method in `PluginUploadIntentStore` was intended to allow clearing the intent by not explicitly setting it.
This change updates the type definitions to `UploadIntent | null` to accurately reflect the possibility of the intent being null, allowing the clearing of the upload intent state.

* fix(ui): add role button to upload selection cards

Adds the `role="button"` attribute to the `nb-card` elements within the upload selection component. This improves accessibility by clearly indicating that these cards are interactive elements that can be activated using a mouse or keyboard.

* fix(desktop-ui-lib): update aria-label for close button

The aria-label for the close button in the upload selection component was previously hardcoded. This commit updates it to use the translated string 'BUTTONS.CLOSE' for better internationalization.

* feat(plugins): internationalize plugin marketplace details

This commit introduces internationalization for various text elements within the plugin marketplace detail view.
Key changes include:
- Translating labels such as "by", "downloads", "Free", "No description available", "Subscription Required", "Installing...", "Uninstalling...", "Trial", "Updated", "License", "Released", and "more tags".
- Localizing the dynamic text for install/uninstall progress.
- Translating the labels for the install toggle button based on plugin status and plan.
- Internationalizing the action menu items for plugins, including "View Details", "Settings", "Manage Subscription", "Manage Users", "Homepage", "Repository", "Edit Plugin", and "Delete".
This enhancement improves the accessibility and usability of the plugin marketplace for a global audience.

* fix(plugins): update scss for gradient and button alignment

Refactors the linear gradient calculation in `add-plugin.component.scss` to use `color-mix` for better theme integration. Adjusts `plugin-list.component.scss` to change `justify-content` from `stretch` to `flex-start` for improved button alignment.

* refactor(plugin-list): extract smart table settings to a method

Extract the `smartTableSettings` object into a dedicated `buildSmartTableSettings` method. This improves code organization and makes it easier to reinitialize settings, especially when the language changes.
This change also moves the call to `loadPlugins()` to `ngAfterViewInit` to ensure that the table settings are fully initialized before attempting to load plugins. This addresses a potential race condition.

* fix(ui): adjust button sizes and styling in plugin components

Update the `size` attribute for close buttons in both the `add-plugin` and `upload-selection` components from `tiny` to `small`. This ensures a consistent and more appropriately sized close button across these plugin-related UI elements.
Additionally, the SCSS for the `.close-button` in `add-plugin.component.scss` has been updated to use `var(--border-radius)` for its `border-radius` property, aligning with global theming. Padding has also been added to `.close-button` in both components for better visual spacing.

* fix(desktop-ui-lib): use theme variable for card shadows

Refactors the shadow styles in the upload selection component to use the `--gauzy-shadow` theme variable. This ensures consistency in the application's visual styling and makes it easier to manage shadows across different components.
* fix: improve error logging format in plugin subscription plan service

* fix(plugin-system): enhance zip extraction security

This commit introduces several security enhancements to the zip extraction process within the CDN download strategy.
Previously, there was a potential for path traversal vulnerabilities if a malicious zip file contained entries with paths that attempted to escape the designated extraction directory.
The following changes were implemented:
- Added a check to ensure the resolved file path of an entry is strictly within the base extraction directory. If it escapes, the entry is logged and skipped.
- Explicitly ensured that the parent directory for each file being extracted exists before attempting to write the file. This prevents errors and potential issues with nested directories within zip archives.
- Refactored `isSafePath` to more robustly handle Windows path separators, disallow absolute paths and drive letters, and ensure the resolved target path starts with the resolved root directory, preventing traversal.

* fix(plugin-category): simplify slug generation logic

* fix(cspell): add new words to the spell checker dictionary

* fix(cdn-download): use replaceAll for entry path normalization
fix(plugin-category): refine slug generation regex for leading/trailing dashes

* fix(cspell): remove duplicated word "Zrdm" from the spell checker dictionary

* fix(cdn-download): improve file extraction handling and add error tracking

* fix(cdn-download): correct path normalization logic in isSafePath method

* fix: arbitrary file access during archive extraction ("Zip Slip")

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* fix(cdn-download): enhance security by rejecting Unix-style absolute paths and removing redundant path validation

* fix(cdn-download): update import for finished stream utility and remove redundant baseExtractPath variable

* fix(cdn-download): improve path normalization

The previous regex ` /\\/g ` for normalizing Windows path separators in `entryPath` was overly broad and could lead to incorrect path normalization in certain edge cases.
This change updates the `replaceAll` method to use a literal backslash character `'\'` instead of a regex, ensuring only backslashes are replaced with forward slashes. This provides more precise and reliable path normalization.

* refactor(cdn-download): simplify archive extraction logic

Refactors the `CdnDownloadStrategy` to use dedicated helper methods for directory creation and file extraction. This improves readability and maintainability of the archive processing logic.
The changes include:
- Extracting directory creation into `createDirectory`.
- Extracting file writing logic into `extractFile`.
- Renaming `filePath` to `entryPath` for clarity.
- Using `path.resolve` for safer path handling.
- Ensuring `entry.autodrain()` is called in error scenarios.

* fix(cdn-download): prevent path traversal in zip extraction

Add validation to the `extractEntry` function to prevent path traversal vulnerabilities during the extraction of zip archives. The target path is now resolved against the base directory of the extraction to ensure it remains within the intended scope.
This change enhances security by ensuring that malicious zip archives cannot write files outside of their designated extraction directory.
The `baseDir` option is now passed to `extractEntry` and used to construct a safe target path.

* fix(plugin-system): improve error handling and stream management in cdn download

This commit addresses several issues in the `CdnDownloadStrategy` related to error handling and stream management during plugin downloads.
Key changes:
- **Robust Error Logging:** Error messages for directory creation and file extraction now include the full error stack or message for better debugging. They also explicitly convert non-Error objects to strings.
- **Stream Pipeline for Extraction:** The `entry.pipe(writeStream)` and `finished(writeStream)` combination has been replaced with `pipeline(entry, writeStream)`. This provides more reliable error propagation and ensures streams are properly cleaned up.
- **Resource Cleanup on Error:** In the `extractFile` method, if an error occurs during file extraction, the `entry` and `writeStream` are explicitly destroyed to release resources.
- **Incomplete File Removal:** If an error occurs during file extraction, any partially created target file is now removed to prevent leaving incomplete artifacts. This handles potential `ENOENT` errors gracefully.
- **Throwing Errors:** Errors are now consistently re-thrown after cleanup, ensuring that the calling code is aware of and can handle extraction failures.

* fix(cdn-download): re-throw stream write errors

The previous implementation of `CdnDownloadStrategy` caught stream write errors and autodrained the entry. This masked the underlying error and prevented `Promise.all` from rejecting, leading to silent failures when downloading plugin files.
This change re-throws the caught error. This ensures that any failure during the file writing process is propagated up to `Promise.all`, allowing the overall download operation to fail gracefully and be reported to the user.

* fix: Rethrowing here propagates the error, but the unzipper entry stream is no longer drained/destroyed on failure. A write error can leave the entry unread and stall the unzip parse. Drain (or destroy) the entry before rethrowing.

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix(cdn-download): improve error handling and resource cleanup

Add robust error handling to the CDN download strategy. This includes:
- Logging detailed error messages, including stack traces when available.
- Destroying pipe streams to release resources on error.
- Attempting to remove incomplete files to prevent corrupted downloads.
- Handling potential errors during file removal (e.g., if the file doesn't exist).
- Ensuring the `entry` stream is also handled correctly on error.

* fix(cdn-download): ensure error is thrown in stream pipe

The previous implementation incorrectly called `entry.autodrain()` before re-throwing the error. This prevented the error from being propagated correctly, potentially leading to unhandled promise rejections.
This change ensures that the error is thrown immediately, allowing the calling code to catch and handle it as expected.

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Bumps [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) from 1.24.0 to 1.25.2.
- [Release notes](https://github.com/modelcontextprotocol/typescript-sdk/releases)
- [Commits](modelcontextprotocol/typescript-sdk@1.24.0...v1.25.2)

---
updated-dependencies:
- dependency-name: "@modelcontextprotocol/sdk"
  dependency-version: 1.25.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
)

Bumps [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) from 1.24.0 to 1.25.2.
- [Release notes](https://github.com/modelcontextprotocol/typescript-sdk/releases)
- [Commits](modelcontextprotocol/typescript-sdk@1.24.0...v1.25.2)

---
updated-dependencies:
- dependency-name: "@modelcontextprotocol/sdk"
  dependency-version: 1.25.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch stage

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@evereq evereq merged commit fa827d1 into stage-apps Jan 8, 2026
15 of 16 checks passed
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

@cla-assistant
Copy link

cla-assistant bot commented Jan 8, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
6 out of 7 committers have signed the CLA.

✅ syns2191
✅ evereq
✅ GloireMutaliko21
✅ adkif
✅ rahul-rocket
✅ samuelmbabhazi
❌ dependabot[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

3 similar comments
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 8, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
11.4% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

Copy link
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 284 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

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=".scripts/electron-package-utils/package-util.ts">

<violation number="1" location=".scripts/electron-package-utils/package-util.ts:44">
P1: Logic bug: `preparePublishChannel()` skips the `prepare()` step. When `arch` and `platform` (linux/win32) are provided, `prepare()` is never called, so essential package properties (name, productName, appId, etc.) won't be set. The `preparePublishChannel` method should be called *in addition to* `prepare()`, not *instead of* it.</violation>
</file>

<file name=".scripts/icon-utils/concrete-generators/desktop-icon-generator.ts">

<violation number="1" location=".scripts/icon-utils/concrete-generators/desktop-icon-generator.ts:203">
P2: The downloaded tray icon file is never cleaned up. Add `await this.remove(trayIconFilePath);` after processing to prevent temporary file accumulation.</violation>
</file>

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

Comment on lines +44 to +45
if (this.instance.arch && this.instance.platform && ['linux', 'win32'].includes(this.instance.platform)) {
packed = packager.preparePublishChannel(pkg, this.instance.arch);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 8, 2026

Choose a reason for hiding this comment

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

P1: Logic bug: preparePublishChannel() skips the prepare() step. When arch and platform (linux/win32) are provided, prepare() is never called, so essential package properties (name, productName, appId, etc.) won't be set. The preparePublishChannel method should be called in addition to prepare(), not instead of it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .scripts/electron-package-utils/package-util.ts, line 44:

<comment>Logic bug: `preparePublishChannel()` skips the `prepare()` step. When `arch` and `platform` (linux/win32) are provided, `prepare()` is never called, so essential package properties (name, productName, appId, etc.) won't be set. The `preparePublishChannel` method should be called *in addition to* `prepare()`, not *instead of* it.</comment>

<file context>
@@ -35,7 +40,12 @@ export class PackageUtil {
 			const packager = PackagerFactory.packager(this.instance.desktop);
-			const packed = packager.prepare(pkg);
+			let packed: IPackage;
+			if (this.instance.arch && this.instance.platform && ['linux', 'win32'].includes(this.instance.platform)) {
+				packed = packager.preparePublishChannel(pkg, this.instance.arch);
+			} else {
</file context>
Suggested change
if (this.instance.arch && this.instance.platform && ['linux', 'win32'].includes(this.instance.platform)) {
packed = packager.preparePublishChannel(pkg, this.instance.arch);
packed = packager.prepare(pkg);
if (this.instance.arch && this.instance.platform && ['linux', 'win32'].includes(this.instance.platform)) {
packed = packager.preparePublishChannel(packed, this.instance.arch);
Fix with Cubic

public async generate(): Promise<void> {
try {
const filePath = await this.downloadImage();
const trayIconFilePath = await this.downloadTrayImage();
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 8, 2026

Choose a reason for hiding this comment

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

P2: The downloaded tray icon file is never cleaned up. Add await this.remove(trayIconFilePath); after processing to prevent temporary file accumulation.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .scripts/icon-utils/concrete-generators/desktop-icon-generator.ts, line 203:

<comment>The downloaded tray icon file is never cleaned up. Add `await this.remove(trayIconFilePath);` after processing to prevent temporary file accumulation.</comment>

<file context>
@@ -186,15 +188,21 @@ export class DesktopIconGenerator
 	public async generate(): Promise<void> {
 		try {
 			const filePath = await this.downloadImage();
+			const trayIconFilePath = await this.downloadTrayImage();
 			if (filePath) {
-				await this.resizeAndConvert(filePath);
</file context>
Fix with Cubic

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

3 similar comments
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 8, 2026

Too many files changed for review.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants