Skip to content

Conversation

@evereq
Copy link
Member

@evereq evereq commented Dec 6, 2025

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

Adds employee recent visits with an API and event-based tracking, improves agent window management and screen-capture flow, and fixes SQLite activity log insert errors. Also adds URL activity tracking and smarter invite filters.

  • New Features

    • Employee recent visits: new module, endpoint, and events; logs visits when opening tasks/projects; supports filters.
    • Agent logs: buffer up to 200 entries and preload into the dashboard via IPC.
    • Screen capture: new notification window with renderer-ready handshake and auto-hide.
    • Desktop activity: track APP and URL separately and push the correct activity type.
  • Bug Fixes

    • SQLite activity logs: serialize JSON fields before insert and deserialize on read to prevent “Too many parameter values”.
    • Invite filters: backend supports LIKE searches and expired/non-expired (including “never expire”); UI adds email, invited-by, status, and expiry toggles.
    • Window handling: safer dashboard show/close; tray/menu use the new show method.
    • Electron i18n path: resolve via ELECTRON_RESOURCES_PATH to fix integrated server startup.

Written for commit 15f7697. Summary will update automatically on new commits.

syns2191 and others added 9 commits December 2, 2025 08:56
fix: agent window management and browser url tracking
* feat(activity-log): add sanitizeEntityForActivityLog helper for SQLite

Add a new helper function that sanitizes entity data before activity logging
to prevent SQLite's 'Too many parameter values' error (SQLITE_MAX_VARIABLE_NUMBER = 999).

For SQLite/BetterSQLite3 only:
- Replaces relation arrays (members, teams, etc.) with ID arrays
- Keeps only primitive values and dates
- Skips nested relation objects

For PostgreSQL/MySQL: Returns the original entity unchanged.

Fixes #9243

* fix(activity-log): sanitize data before logging to prevent SQLite error

Apply sanitizeEntityForActivityLog to entity data in logActivity method
before publishing the ActivityLogEvent.

This prevents the 'RangeError: Too many parameter values' error when
creating/updating tasks with multiple members/teams on BetterSQLite3.

Fixes #9243

* feat(activity-log): add serializeActivityLogForSqlite helper function

Add helper function to serialize JSON fields (data, updatedFields, previousValues,
updatedValues, previousEntities, updatedEntities) to strings before database insert.

This prevents SQLite's 'Too many parameter values' error (SQLITE_MAX_VARIABLE_NUMBER = 999)
when creating activity logs with large nested objects.

Fixes #9243

* fix(activity-log): serialize JSON fields before insert for SQLite

Use serializeActivityLogForSqlite helper in create() method to stringify
JSON fields before passing to TypeORM for SQLite/BetterSQLite3 databases.

This fixes the 'RangeError: Too many parameter values were provided' error
when creating tasks with multiple members/teams.

Fixes #9243

* fix(activity-log): add updatedFields to SQLite deserialization

Add missing 'updatedFields' to afterEntityLoad deserialization to ensure
the field is properly parsed from JSON string when reading from SQLite.

Fixes #9243
* feat: created the employee recent visits module, service and events

* feat: get the employee recent visits based on options

* fix: updated the employee recent visits module

* feat: register recent visits for projects and tasks

* fix: deepscan issue

* fix: store all the employee visits and add return filters

* fix: AI suggestions

* fix: AI suggestions

* fix: registered the employee recent visits module

* fix: refactored the existing check using repository

* fix: improved dto and service filters
Bumps [jws](https://github.com/brianloveswords/node-jws) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/brianloveswords/node-jws/releases)
- [Changelog](https://github.com/auth0/node-jws/blob/master/CHANGELOG.md)
- [Commits](auth0/node-jws@v3.2.2...v3.2.3)

---
updated-dependencies:
- dependency-name: jws
  dependency-version: 3.2.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Bumps [jws](https://github.com/brianloveswords/node-jws) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/brianloveswords/node-jws/releases)
- [Changelog](https://github.com/auth0/node-jws/blob/master/CHANGELOG.md)
- [Commits](auth0/node-jws@v3.2.2...v3.2.3)

---
updated-dependencies:
- dependency-name: jws
  dependency-version: 3.2.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [nodemailer](https://github.com/nodemailer/nodemailer) from 7.0.9 to 7.0.11.
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](nodemailer/nodemailer@v7.0.9...v7.0.11)

---
updated-dependencies:
- dependency-name: nodemailer
  dependency-version: 7.0.11
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
…ler-7.0.11

chore(deps): bump nodemailer from 7.0.9 to 7.0.11
* feat(table-filters): add InviteStatusFilterComponent for invite status dropdown

* feat(invites): add smart table filters for email, fullName, expireDate, and status columns

* feat(invite): add backend support for LIKE filters on email/invitedByUser and isExpired toggle filter

* fix(table-filters): improve InviteStatusFilterComponent - remove empty ngOnChanges, mark inviteStatuses as protected, handle null on filter clear

* refactor(invites): use _getFilterFunction for fullName column filter

* refactor(invite): reduce code duplication and add IsNull for non-expired filter

- Extract role, projects, teams from restWhere to avoid duplicate filter application
- Add helper functions buildBaseCondition and buildInvitedByUserCondition
- Include IsNull() condition for non-expired filter to handle 'Never expire' invites
- Add comments explaining boolean coercion from query params

* refactor(table-filters): remove redundant constructor from InviteStatusFilterComponent

* fix(invite): add defensive array handling for projects and teams filters

Align with roleFilter pattern by handling both object with id property
and direct array formats to prevent runtime errors from query params.
* fix: desktop integrated server failed to started

* fix: desktop integrated server failed to started

* Update apps/desktop/src/index.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: Ruslan Konviser <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 6, 2025

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 develop

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.

@CLAassistant
Copy link

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.
4 out of 5 committers have signed the CLA.

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

@evereq evereq merged commit 0fc9572 into stage Dec 6, 2025
23 of 28 checks passed
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 6, 2025

Greptile Overview

Greptile Summary

This PR merges multiple feature enhancements and bug fixes from the develop branch into stage, including:

  • Employee Recent Visit Tracking: New feature to track and retrieve employee visits to entities (projects, tasks, etc.) with event-driven architecture
  • Enhanced Invite Filtering: Added comprehensive filtering capabilities including email search, expiration status, invited-by name search, and status filtering with proper OR conditions for multi-field searches
  • Desktop Activity Tracking Improvements: Fixed activity tracking to properly separate URL and APP activities using composite keys, preventing data aggregation issues
  • Notification Window Lifecycle: Refactored screen capture notification handling with improved ready-state tracking and auto-hide behavior
  • Security Updates: Updated nodemailer (7.0.9 → 7.0.11) and jws (3.2.2 → 3.2.3) dependencies
  • i18n Configuration: Added internationalization directories to asarUnpack configuration for proper file access in packaged applications

The changes are well-structured with proper type safety improvements and defensive coding patterns.

Confidence Score: 4/5

  • This PR is generally safe to merge with one critical logic issue that should be addressed
  • The PR contains well-structured features with proper type safety and defensive coding. However, there's a recursive function in window-manager.ts that could cause infinite recursion/stack overflow if the window never loads, which is a critical issue that should be fixed before merging. The rest of the changes are solid improvements including security patches.
  • Review apps/agent/src/main/window-manager.ts - fix the recursive isWindowReadyToShow function to prevent potential infinite recursion

Important Files Changed

File Analysis

Filename Score Overview
apps/agent/src/main/window-manager.ts 3/5 Refactored notification window lifecycle with improved ready-state tracking and auto-hide behavior; includes recursive function that could cause infinite recursion if window never loads
packages/desktop-activity/src/lib/activity-window.ts 5/5 Improved activity tracking to separate URL and APP activities with distinct keys, preventing data loss; simplified meta array to single object
packages/core/src/lib/employee-recent-visit/employee-recent-visit.service.ts 5/5 New service for tracking employee recent visits with event-driven architecture and proper pagination logic
packages/core/src/lib/invite/invite.service.ts 5/5 Enhanced invite filtering with email search, expiration status filtering, and proper handling of multi-field name searches using OR conditions
packages/ui-core/shared/src/lib/invite/invites/invites.component.ts 5/5 Added column-level filtering for email, invited by user, expiration, and status with custom filter components
packages/desktop-activity/src/lib/i-kb-mouse.ts 5/5 Fixed type definitions - changed meta from array to single object and added type field to TWindowActivities

Sequence Diagram

sequenceDiagram
    participant User
    participant AgentApp
    participant WindowManager
    participant ScreenCaptureWindow
    participant NotificationUI
    participant ActivityWindow
    participant DesktopActivity
    participant BackendAPI
    participant EmployeeRecentVisitService
    participant InviteService

    Note over User,InviteService: Desktop Agent: Screen Capture & Activity Tracking
    User->>AgentApp: Start tracking
    AgentApp->>WindowManager: initScreenShotNotification()
    WindowManager->>ScreenCaptureWindow: new ScreenCaptureWindow()
    ScreenCaptureWindow->>ScreenCaptureWindow: loadURL()
    
    loop Every tracking interval
        AgentApp->>ActivityWindow: getActiveWindowAndSetDuration()
        ActivityWindow->>DesktopActivity: getActiveWindow()
        DesktopActivity-->>ActivityWindow: currentActiveWindow
        ActivityWindow->>ActivityWindow: updateWindowActivities(APP)
        alt Has URL
            ActivityWindow->>ActivityWindow: updateWindowActivities(URL)
        end
    end
    
    AgentApp->>WindowManager: showNotificationWindow(thumbUrl)
    WindowManager->>WindowManager: isWindowReadyToShow() [recursive]
    WindowManager->>NotificationUI: send('show_popup_screen_capture')
    WindowManager->>NotificationUI: showInactive()
    WindowManager->>WindowManager: setTimeout(hideNotificationWindow, 3000)
    
    Note over User,InviteService: Backend: Employee Recent Visits
    User->>BackendAPI: Visit project/task
    BackendAPI->>EmployeeRecentVisitService: emitSaveEmployeeRecentVisitEvent()
    EmployeeRecentVisitService->>EmployeeRecentVisitService: EventBus.publish()
    EmployeeRecentVisitService->>EmployeeRecentVisitService: create(visitData)
    alt Existing entry
        EmployeeRecentVisitService->>EmployeeRecentVisitService: Update visitedAt
    else New entry
        EmployeeRecentVisitService->>EmployeeRecentVisitService: Create new entry
    end
    EmployeeRecentVisitService-->>BackendAPI: Recent visit saved
    
    Note over User,InviteService: Backend: Enhanced Invite Filtering
    User->>BackendAPI: GET /invites?email=john&isExpired=false
    BackendAPI->>InviteService: findAllInvites(filters)
    InviteService->>InviteService: buildWhereConditions()
    alt Email filter
        InviteService->>InviteService: Add LIKE email filter
    end
    alt Expiration filter
        InviteService->>InviteService: Add expireDate >= now OR IS NULL
    end
    alt InvitedByUser filter
        InviteService->>InviteService: OR (firstName LIKE, lastName LIKE)
    end
    InviteService-->>BackendAPI: Filtered invites
    BackendAPI-->>User: Display invites
Loading

Copy link
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.

46 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +284 to +290
async isWindowReadyToShow(window: BrowserWindow, windowType: WindowType) {
await delaySync(200);
if (!window?.webContents?.isLoading?.() && (windowType !== WindowType.notificationWindow || this.windowReadyStatus[windowType])) {
return true;
}
return this.isWindowReadyToShow(window, windowType);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: this recursive function could cause a stack overflow if the window never finishes loading or if windowReadyStatus[windowType] is never set to true

Suggested change
async isWindowReadyToShow(window: BrowserWindow, windowType: WindowType) {
await delaySync(200);
if (!window?.webContents?.isLoading?.() && (windowType !== WindowType.notificationWindow || this.windowReadyStatus[windowType])) {
return true;
}
return this.isWindowReadyToShow(window, windowType);
}
async isWindowReadyToShow(window: BrowserWindow, windowType: WindowType, maxRetries = 50): Promise<boolean> {
if (maxRetries <= 0) {
console.error(`Window ${windowType} failed to become ready after maximum retries`);
return false;
}
await delaySync(200);
if (!window?.webContents?.isLoading?.() && (windowType !== WindowType.notificationWindow || this.windowReadyStatus[windowType])) {
return true;
}
return this.isWindowReadyToShow(window, windowType, maxRetries - 1);
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/agent/src/main/window-manager.ts
Line: 284:290

Comment:
**logic:** this recursive function could cause a stack overflow if the window never finishes loading or if `windowReadyStatus[windowType]` is never set to true

```suggestion
	async isWindowReadyToShow(window: BrowserWindow, windowType: WindowType, maxRetries = 50): Promise<boolean> {
		if (maxRetries <= 0) {
			console.error(`Window ${windowType} failed to become ready after maximum retries`);
			return false;
		}
		await delaySync(200);
		if (!window?.webContents?.isLoading?.() && (windowType !== WindowType.notificationWindow || this.windowReadyStatus[windowType])) {
			return true;
		}
		return this.isWindowReadyToShow(window, windowType, maxRetries - 1);
	}
```

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

dashboardWindow: boolean;
};
private static instance: AppWindow;
private autoHideTimeout: NodeJS.Timeout | null = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

syntax: inconsistent indentation - this line uses spaces while the rest of the class uses tabs

Suggested change
private autoHideTimeout: NodeJS.Timeout | null = null;
private autoHideTimeout: NodeJS.Timeout | null = null;
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/agent/src/main/window-manager.ts
Line: 44:44

Comment:
**syntax:** inconsistent indentation - this line uses spaces while the rest of the class uses tabs

```suggestion
	private autoHideTimeout: NodeJS.Timeout | null = null;
```

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

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.

4 issues found across 48 files

Prompt for AI agents (all 4 issues)

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


<file name="apps/agent/src/main/window/screen-capture-window.ts">

<violation number="1" location="apps/agent/src/main/window/screen-capture-window.ts:17">
P3: Grammatically incorrect warning message. Consider rephrasing to: `&#39;This method should not be called directly&#39;` or `&#39;Direct calls to this method are not supported&#39;`.</violation>
</file>

<file name="packages/desktop-ui-lib/src/lib/agent-dashboard/services/logs.service.ts">

<violation number="1" location="packages/desktop-ui-lib/src/lib/agent-dashboard/services/logs.service.ts:96">
P2: Missing null/undefined check before iterating over `cacheLogs`. If the IPC call returns `null` or `undefined`, the `for...of` loop will throw a `TypeError`. Consider adding a guard clause or defaulting to an empty array.</violation>
</file>

<file name="packages/core/src/lib/employee-recent-visit/employee-recent-visit.controller.ts">

<violation number="1" location="packages/core/src/lib/employee-recent-visit/employee-recent-visit.controller.ts:10">
P2: `@Permissions()` is called without any arguments while `PermissionGuard` is in use. When no permissions are specified, `PermissionGuard` bypasses authorization checks entirely (returns `true`). Either specify the required permissions (e.g., `@Permissions(PermissionsEnum.SOME_PERMISSION)`) or remove `PermissionGuard` from the guards if no specific permission is needed.</violation>
</file>

<file name="packages/core/src/lib/activity-log/activity-log.subscriber.ts">

<violation number="1" location="packages/core/src/lib/activity-log/activity-log.subscriber.ts:119">
P2: Missing corresponding serialization for `updatedFields`. This field is now being deserialized in `afterEntityLoad`, but it&#39;s not included in the `serializeFields` call within `serializeDataForSQLite`. This asymmetry could cause issues when loading SQLite data that wasn&#39;t properly serialized. The `serializeDataForSQLite` method should also include `&#39;updatedFields&#39;` in its serialization array.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

}

override hide(): void {
console.warn('Prevent this method to directly call');
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 6, 2025

Choose a reason for hiding this comment

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

P3: Grammatically incorrect warning message. Consider rephrasing to: 'This method should not be called directly' or 'Direct calls to this method are not supported'.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/agent/src/main/window/screen-capture-window.ts, line 17:

<comment>Grammatically incorrect warning message. Consider rephrasing to: `&#39;This method should not be called directly&#39;` or `&#39;Direct calls to this method are not supported&#39;`.</comment>

<file context>
@@ -0,0 +1,19 @@
+	}
+
+	override hide(): void {
+	    console.warn(&#39;Prevent this method to directly call&#39;);
+	}
+}
</file context>
Suggested change
console.warn('Prevent this method to directly call');
console.warn('This method should not be called directly');
Fix with Cubic


async loadLogs() {
const cacheLogs: Record<string, any>[] = await this.electronService.ipcRenderer.invoke('load_logs');
for (const logContent of cacheLogs) {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 6, 2025

Choose a reason for hiding this comment

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

P2: Missing null/undefined check before iterating over cacheLogs. If the IPC call returns null or undefined, the for...of loop will throw a TypeError. Consider adding a guard clause or defaulting to an empty array.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/desktop-ui-lib/src/lib/agent-dashboard/services/logs.service.ts, line 96:

<comment>Missing null/undefined check before iterating over `cacheLogs`. If the IPC call returns `null` or `undefined`, the `for...of` loop will throw a `TypeError`. Consider adding a guard clause or defaulting to an empty array.</comment>

<file context>
@@ -90,4 +90,11 @@ export class LogService {
+
+	async loadLogs() {
+		const cacheLogs: Record&lt;string, any&gt;[] = await this.electronService.ipcRenderer.invoke(&#39;load_logs&#39;);
+		for (const logContent of cacheLogs) {
+			this.handleLogStream(logContent);
+		}
</file context>
Suggested change
for (const logContent of cacheLogs) {
for (const logContent of cacheLogs ?? []) {
Fix with Cubic

import { GetEmployeeRecentVisitsDTO } from './dto/get-employee-recent-visits.dto';

@UseGuards(TenantPermissionGuard, PermissionGuard)
@Permissions()
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 6, 2025

Choose a reason for hiding this comment

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

P2: @Permissions() is called without any arguments while PermissionGuard is in use. When no permissions are specified, PermissionGuard bypasses authorization checks entirely (returns true). Either specify the required permissions (e.g., @Permissions(PermissionsEnum.SOME_PERMISSION)) or remove PermissionGuard from the guards if no specific permission is needed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/lib/employee-recent-visit/employee-recent-visit.controller.ts, line 10:

<comment>`@Permissions()` is called without any arguments while `PermissionGuard` is in use. When no permissions are specified, `PermissionGuard` bypasses authorization checks entirely (returns `true`). Either specify the required permissions (e.g., `@Permissions(PermissionsEnum.SOME_PERMISSION)`) or remove `PermissionGuard` from the guards if no specific permission is needed.</comment>

<file context>
@@ -0,0 +1,29 @@
+import { GetEmployeeRecentVisitsDTO } from &#39;./dto/get-employee-recent-visits.dto&#39;;
+
+@UseGuards(TenantPermissionGuard, PermissionGuard)
+@Permissions()
+@Controller(&#39;/employee-recent-visit&#39;)
+export class EmployeeRecentVisitController {
</file context>
Fix with Cubic

// Parse `updatedValues`, `previousValues`, `updatedEntities`, `previousEntities` if they are strings
// Parse `updatedFields`, `updatedValues`, `previousValues`, `updatedEntities`, `previousEntities` if they are strings
this.deserializeFields(entity, [
'updatedFields',
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 6, 2025

Choose a reason for hiding this comment

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

P2: Missing corresponding serialization for updatedFields. This field is now being deserialized in afterEntityLoad, but it's not included in the serializeFields call within serializeDataForSQLite. This asymmetry could cause issues when loading SQLite data that wasn't properly serialized. The serializeDataForSQLite method should also include 'updatedFields' in its serialization array.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/lib/activity-log/activity-log.subscriber.ts, line 119:

<comment>Missing corresponding serialization for `updatedFields`. This field is now being deserialized in `afterEntityLoad`, but it&#39;s not included in the `serializeFields` call within `serializeDataForSQLite`. This asymmetry could cause issues when loading SQLite data that wasn&#39;t properly serialized. The `serializeDataForSQLite` method should also include `&#39;updatedFields&#39;` in its serialization array.</comment>

<file context>
@@ -114,8 +114,9 @@ export class ActivityLogSubscriber extends BaseEntityEventSubscriber&lt;ActivityLog
-				// Parse `updatedValues`, `previousValues`, `updatedEntities`, `previousEntities` if they are strings
+				// Parse `updatedFields`, `updatedValues`, `previousValues`, `updatedEntities`, `previousEntities` if they are strings
 				this.deserializeFields(entity, [
+					&#39;updatedFields&#39;,
 					&#39;updatedValues&#39;,
 					&#39;previousValues&#39;,
</file context>
Fix with Cubic

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.

6 participants