Merge changes I181a46f1,I4e81a0a7

* changes:
  Remove index-only entries after (re)index with --reuse option
  AllChangesIndexer: create ChangeIndexer as early as possible
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index dc0f346..5f09c03 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1507,7 +1507,7 @@
 
 [[change.commentSizeLimit]]change.commentSizeLimit::
 +
-Maximum allowed size in characters of a regular (non-robot) comment. Comments
+Maximum allowed size in characters of a comment. Comments
 which exceed this size will be rejected. Size computation is approximate and may
 be off by roughly 1%. Common unit suffixes of 'k', 'm', or 'g' are supported.
 The value must be positive.
@@ -1523,7 +1523,7 @@
 
 [[change.cumulativeCommentSizeLimit]]change.cumulativeCommentSizeLimit::
 +
-Maximum allowed size in characters of all comments (including robot comments)
+Maximum allowed size in characters of all comments
 and change messages. Size computation is approximate and may be off by roughly
 1%. Common unit suffixes of 'k', 'm', or 'g' are supported.
 +
@@ -1537,7 +1537,7 @@
 
 [[change.maxComments]]change.maxComments::
 +
-Maximum number of comments (regular plus robot) allowed per change. Additional
+Maximum number of comments allowed per change. Additional
 comments are rejected.
 +
 By default 5,000.
@@ -1570,7 +1570,7 @@
 [[change.maxUpdates]]change.maxUpdates::
 +
 Maximum number of updates to a change. Counts only updates to the main NoteDb
-meta ref; draft comments, robot comments, stars, etc. do not count towards the
+meta ref; draft comments, stars, etc. do not count towards the
 total.
 +
 Many NoteDb operations require walking the entire change meta ref and loading
@@ -1654,10 +1654,15 @@
 +
 By default `true`.
 
-[[change.enableRobotComments]]change.enableRobotComments::
+[[change.allowMarkdownBase64ImagesInComments]]change.allowMarkdownBase64ImagesInComments::
 +
-Are robot comments enabled in the Gerrit UI? This setting allows phasing out
-robot comments. Soon robot comments will be entirely removed.
+Allows Base64 encoded images, embedded via Markdown, to be rendered in Gerrit comments.
++
+This feature addresses the need for teams to share images directly within Gerrit comments.
+Instead of relying on external image hosting, images are encoded into Base64 strings
+and included in the comment text using Markdown image syntax.
++
+When enabled, the Gerrit UI will detect and render these inline images.
 +
 By default `false`.
 
@@ -1690,15 +1695,6 @@
 than handling parsing errors gracefully, which can make Gerrit for impacted
 users unusable.
 
-[[change.robotCommentSizeLimit]]change.robotCommentSizeLimit::
-+
-Maximum allowed size in characters of a robot comment. Robot comments which
-exceed this size will be rejected on addition. Size computation is approximate
-and may be off by roughly 1%. Common unit suffixes of 'k', 'm', or 'g' are
-supported. Zero or negative values allow robot comments of unlimited size.
-+
-The default limit is 1MiB.
-
 [[change.sendNewPatchsetEmails]]change.sendNewPatchsetEmails::
 +
 When `false`, emails will not be sent to owners, reviewers, and cc for
@@ -2353,6 +2349,15 @@
 The list of submit requirement names that should be displayed as separate
 columns in the dashboard.
 
+[[dashboard.showAllLabels]]dashboard.showAllLabels::
++
+Display all labels in the dashboard, even if they are not submit
+requirements.
++
+This has no effect if submitRequirementColumns is configured.
++
+Default is `false`.
+
 [[download]]
 === Section download
 
@@ -4100,7 +4105,7 @@
 +
 Add patch set level comment as event comment. Without this option, patch set
 level comment will not be included in the event comment attribute. Given that
-currently patch set level, file and robot comments are not exposed in the
+currently patch set level and file comments are not exposed in the
 `comment-added` event type, those comments will be lost. One particular use
 case is to re-trigger CI build from the change screen by adding a comment with
 specific content, e.g.: `recheck`. Jenkins Gerrit Trigger plugin and Zuul CI
@@ -5248,6 +5253,42 @@
 +
 Path must be absolute.
 
+[[repository.name.defaultConfig]]repository.<name>.defaultConfig::
++
+Sets the default value for boolean project configs:
++
+--
+* link:config-project-config.html#change.privateByDefault[change.privateByDefault]
+* link:config-project-config.html#change.workInProgressByDefault[change.workInProgressByDefault]
+* link:config-project-config.html#receive.createNewChangeForAllNotInTarget[receive.createNewChangeForAllNotInTarget]
+* link:config-project-config.html#receive.enableSignedPush[receive.enableSignedPush]
+* link:config-project-config.html#receive.requireChangeId[receive.requireChangeId]
+* link:config-project-config.html#receive.requireContributorAgreement[receive.requireContributorAgreement]
+* link:config-project-config.html#receive.rejectImplicitMerges[receive.rejectImplicitMerges]
+* link:config-project-config.html#receive.requireSignedOffBy[receive.requireSignedOffBy]
+* link:config-project-config.html#receive.requireSignedPush[receive.requireSignedPush]
+* link:config-project-config.html#reviewer.enableByEmail[reviewer.enableByEmail]
+* link:config-project-config.html#reviewer.skipAddingAuthorAndCommitterAsReviewers[reviewer.skipAddingAuthorAndCommitterAsReviewers]
+* link:config-project-config.html#submit.matchAuthorToCommitterDate[submit.matchAuthorToCommitterDate]
+* link:config-project-config.html#submit.mergeContent[submit.mergeContent]
+* link:config-project-config.html#submit.rejectEmptyCommit[submit.rejectEmptyCommit]
+--
++
+May be specified multiple times.
++
+The values must have the format `<key>=<defaultValue>`, e.g.
+`receive.rejectImplicitMerges=true`.
++
+Allowed default values are:
++
+* `true`: The default value is `true`. Projects may override the default in
+  their project configuration.
+* `forced`: The value is `true` for all projects. Projects cannot override this
+  default in their project configuration (existing configurations for this
+  parameter on project level are ignored).
+* `false`: The default value is `false`. Projects may override the default in
+  their project configuration.
+
 [[repository.name.defaultSubmitType]]repository.<name>.defaultSubmitType::
 +
 The default submit type for newly created projects. Supported values
diff --git a/Documentation/config-robot-comments.txt b/Documentation/config-robot-comments.txt
deleted file mode 100644
index ef99d80..0000000
--- a/Documentation/config-robot-comments.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-= Gerrit Code Review - Robot Comments
-
-[NOTE]
-Robot Comments are deprecated in favour of link:pg-plugin-checks-api.html[Checks API] and human
-comments.
-
-Gerrit has special support for inline comments that are generated by
-automated third-party systems, so called "robot comments". For example
-robot comments can be used to represent the results of code analyzers.
-
-In contrast to regular inline comments which are free-text comments,
-robot comments are more structured and can contain additional data,
-such as a robot ID, a robot run ID and a URL, see
-link:rest-api-changes.html#robot-comment-info[RobotCommentInfo] for
-details.
-
-It is planned to visualize robot comments differently in the web UI so
-that they can be easily distinguished from human comments. Users should
-also be able to use filtering on robot comments, so that only part of
-the robot comments or no robot comments are shown. In addition robot
-comments can contain fixes, that users can apply by a single click.
-
-== REST endpoints
-
-* Posting robot comments is done by the
-  link:rest-api-changes.html[Set Review] REST endpoint. The
-  link:rest-api-changes.html#review-input[input] for this REST endpoint
-  can contain robot comments in its `robot_comments` field.
-* link:rest-api-changes.html#list-robot-comments[List Robot Comments]
-* link:rest-api-changes.html#get-robot-comment[Get Robot Comment]
-
-== Storage
-
-Robot comments are stored per change in a
-`refs/changes/XX/YYYY/robot-comments` ref, where `XX/YYYY` is the
-sharded change ID.
-
-Robot comments can be dropped by deleting this ref.
-
-== Limitations
-
-* There is no support for draft robot comments, but robot comments are
-  always published and visible to everyone who can see the change.
-
-GERRIT
-------
-Part of link:index.html[Gerrit Code Review]
-
-SEARCHBOX
----------
diff --git a/Documentation/index.txt b/Documentation/index.txt
index 5d4a29b..cc9ac6c 100644
--- a/Documentation/index.txt
+++ b/Documentation/index.txt
@@ -63,7 +63,6 @@
 . link:config-hooks.html[Hooks]
 . link:config-mail.html[Mail Templates]
 . link:config-cla.html[Contributor Agreements]
-. link:config-robot-comments.html[Robot Comments]
 
 == Server Administration
 . link:install.html[Installation Guide]
diff --git a/Documentation/note-db.txt b/Documentation/note-db.txt
index 29c794c..5e883fc 100644
--- a/Documentation/note-db.txt
+++ b/Documentation/note-db.txt
@@ -91,12 +91,6 @@
     },
 ----
 
-Automated systems may post "robot comments" instead of normal
-comments, which are an extension of the previous comment, defined in
-the
-link:https://gerrit.googlesource.com/gerrit/\+/master/java/com/google/gerrit/entities/RobotComment.java[RobotComment]
-class.
-
 [[migration]]
 == Migration
 
diff --git a/Documentation/pg-plugin-endpoints.txt b/Documentation/pg-plugin-endpoints.txt
index 08be0bb..fa02fa4 100644
--- a/Documentation/pg-plugin-endpoints.txt
+++ b/Documentation/pg-plugin-endpoints.txt
@@ -124,18 +124,6 @@
 The end point contains the `<gr-formatted-text>` element holding the
 `CheckResult.message` (if any was set).
 
-=== robot-comment-controls
-The `robot-comment-controls` extension point is located inside each comment
-rendered on the diff page, and is only visible when the comment is a robot
-comment, specifically if the comment has a `robot_id` property.
-
-In addition to default parameters, the following are available:
-
-* `comment`
-+
-current comment displayed, an instance of
-link:rest-api-changes.html#comment-info[CommentInfo]
-
 === repo-command
 This endpoint is situated among the repository commands.
 
diff --git a/Documentation/pgm-reindex.txt b/Documentation/pgm-reindex.txt
index 2946d44a..01dc9cd 100644
--- a/Documentation/pgm-reindex.txt
+++ b/Documentation/pgm-reindex.txt
@@ -13,6 +13,7 @@
   [--verbose]
   [--list]
   [--index]
+  [--read-only-disk-caches]
 --
 
 == DESCRIPTION
@@ -55,6 +56,11 @@
 	Without this option a restart recreates the complete index
 	from scratch without reusing existing index documents.
 
+--read-only-disk-caches|--ro-disk-caches::
+    Use read-only disk caches for the reindexing process. This option
+    can be used to avoid writing old data into caches, which might
+    cause performance issues and a lot of disk space being used.
+
 == CONTEXT
 The secondary index must be enabled. See
 link:config-gerrit.html#index.type[index.type].
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 023b5e3..0c30a73 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -2529,62 +2529,6 @@
   }
 ----
 
-[[list-change-robot-comments]]
-=== List Change Robot Comments (deprecated)
---
-'GET /changes/link:#change-id[\{change-id\}]/robotcomments'
---
-
-Lists the robot comments of all revisions of the change.
-
-Return a map that maps the file path to a list of
-link:#robot-comment-info[RobotCommentInfo] entries. The entries in the
-map are sorted by file path.
-
-.Request
-----
-  GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/robotcomments/ HTTP/1.0
-----
-
-.Response
-----
-  HTTP/1.1 200 OK
-  Content-Disposition: attachment
-  Content-Type: application/json; charset=UTF-8
-
-  )]}'
-  {
-    "gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java": [
-      {
-        "id": "TvcXrmjM",
-        "line": 23,
-        "message": "unused import",
-        "updated": "2016-02-26 15:40:43.986000000",
-        "author": {
-          "_account_id": 1000110,
-          "name": "Code Analyzer",
-          "email": "code.analyzer@example.com"
-        },
-        "robot_id": "importChecker",
-        "robot_run_id": "76b1375aa8626ea7149792831fe2ed85e80d9e04"
-      },
-      {
-        "id": "TveXwFiA",
-        "line": 49,
-        "message": "wrong indention",
-        "updated": "2016-02-26 15:40:45.328000000",
-        "author": {
-          "_account_id": 1000110,
-          "name": "Code Analyzer",
-          "email": "code.analyzer@example.com"
-        },
-        "robot_id": "styleChecker",
-        "robot_run_id": "5c606c425dd45184484f9d0a2ffd725a7607839b"
-      }
-    ]
-  }
-----
-
 [[list-change-drafts]]
 === List Change Drafts
 --
@@ -5571,102 +5515,6 @@
   }
 ----
 
-[[list-robot-comments]]
-=== List Robot Comments (deprecated)
---
-'GET /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]/robotcomments/'
---
-
-Lists the link:config-robot-comments.html[robot comments] of a
-revision.
-
-As result a map is returned that maps the file path to a list of
-link:#robot-comment-info[RobotCommentInfo] entries. The entries in the
-map are sorted by file path.
-
-.Request
-----
-  GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/robotcomments/ HTTP/1.0
-----
-
-.Response
-----
-  HTTP/1.1 200 OK
-  Content-Disposition: attachment
-  Content-Type: application/json; charset=UTF-8
-
-  )]}'
-  {
-    "gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java": [
-      {
-        "id": "TvcXrmjM",
-        "line": 23,
-        "message": "unused import",
-        "updated": "2016-02-26 15:40:43.986000000",
-        "author": {
-          "_account_id": 1000110,
-          "name": "Code Analyzer",
-          "email": "code.analyzer@example.com"
-        },
-        "robot_id": "importChecker",
-        "robot_run_id": "76b1375aa8626ea7149792831fe2ed85e80d9e04"
-      },
-      {
-        "id": "TveXwFiA",
-        "line": 49,
-        "message": "wrong indention",
-        "updated": "2016-02-26 15:40:45.328000000",
-        "author": {
-          "_account_id": 1000110,
-          "name": "Code Analyzer",
-          "email": "code.analyzer@example.com"
-        },
-        "robot_id": "styleChecker",
-        "robot_run_id": "5c606c425dd45184484f9d0a2ffd725a7607839b"
-      }
-    ]
-  }
-----
-
-[[get-robot-comment]]
-=== Get Robot Comment (deprecated)
---
-'GET /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]/robotcomments/link:#comment-id[\{comment-id\}]'
---
-
-Retrieves a link:config-robot-comments.html[robot comment] of a
-revision.
-
-.Request
-----
-  GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/robotcomments/TvcXrmjM HTTP/1.0
-----
-
-As response a link:#robot-comment-info[RobotCommentInfo] entity is
-returned that describes the robot comment.
-
-.Response
-----
-  HTTP/1.1 200 OK
-  Content-Disposition: attachment
-  Content-Type: application/json; charset=UTF-8
-
-  )]}'
-  {
-    "id": "TvcXrmjM",
-    "line": 23,
-    "message": "unused import",
-    "updated": "2016-02-26 15:40:43.986000000",
-    "author": {
-      "_account_id": 1000110,
-      "name": "Code Analyzer",
-      "email": "code.analyzer@example.com"
-    },
-    "robot_id": "importChecker",
-    "robot_run_id": "76b1375aa8626ea7149792831fe2ed85e80d9e04"
-  }
-----
-
 [[list-ported-comments]]
 === List Ported Comments
 --
@@ -5680,10 +5528,8 @@
 comments are ported as that logic might change in the future. Instead, callers must be able to
 handle any smaller/larger set of comments returned by this endpoint.
 
-Typically, a comment thread is returned fully or excluded fully. However, draft comments and
-robot comments are ignored and not returned via this endpoint. Hence, it's possible to get ported
-comments from this endpoint which are a reply to a non-ported robot comment. Callers must be
-able to deal with this situation.
+Typically, a comment thread is returned fully or excluded fully. However, draft comments
+are ignored and not returned via this endpoint.
 
 The returned comments are organized in a map of file path to link:#comment-info[CommentInfo] entries
 in the same fashion as for the link:#list-comments[List Revision Comments] endpoint.
@@ -5766,7 +5612,7 @@
 Depending on the filtering rules, it's possible that this endpoint returns a draft comment which is
 a reply to a comment thread which is not returned by the
 link:#list-ported-comments[List Ported Comments] endpoint. That's intended behavior. Callers must be
-able to handle this situation. The same holds for drafts which are a reply to a robot comment.
+able to handle this situation.
 
 Different than the link:#list-ported-comments[List Ported Comments] endpoint, the `author` of the
 returned comments is not filled for this endpoint as only comments of the calling user are returned.
@@ -8199,6 +8045,10 @@
 |`new_mode`        |optional|File mode in octal (e.g. 100644) at the new commit.
 The first three digits indicate the file type and the last three digits contain
 the file permission bits. For deleted files, this field will not be present.
+|`old_sha`        |optional|SHA-1 of the file content at the old commit.
+For added files, this field will not be present.
+|`new_sha`        |optional|SHA-1 of the file content at the new commit.
+For deleted files, this field will not be present.
 |=============================
 
 [[fix-input]]
@@ -8859,9 +8709,6 @@
 |`comments`                             |optional|
 The comments that should be added as a map that maps a file path to a
 list of link:#comment-input[CommentInput] entities.
-|`robot_comments`                       |optional, deprecated|
-The robot comments that should be added as a map that maps a file path
-to a list of link:#robot-comment-input[RobotCommentInput] entities.
 |`drafts`                               |optional|
 Draft handling that defines how draft comments are handled that are
 already in the database but that were not also described in this
@@ -9124,58 +8971,6 @@
 by Gerrit operation).
 |===========================
 
-[[robot-comment-info]]
-=== RobotCommentInfo (deprecated)
-The `RobotCommentInfo` entity contains information about a robot inline
-comment.
-
-`RobotCommentInfo` has the same fields as <<comment-info,CommentInfo>>
-except for the `unresolved` field which doesn't exist for robot comments.
-In addition `RobotCommentInfo` has the following fields:
-
-[options="header",cols="1,^1,5"]
-|===========================
-|Field Name       ||Description
-|`robot_id`       ||The ID of the robot that generated this comment.
-|`robot_run_id`   ||An ID of the run of the robot.
-|`url`            |optional|URL to more information.
-|`properties`     |optional|Robot specific properties as map that maps arbitrary
-keys to values.
-|===========================
-
-[[robot-comment-input]]
-=== RobotCommentInput (deprecated)
-The `RobotCommentInput` entity contains information for creating an inline
-robot comment.
-
-[options="header",cols="1,^1,5"]
-|===========================
-|Field Name    ||Description
-|`path`        ||
-link:#file-id[The file path] for which the inline comment should be added.
-|`side`        |optional|
-The side on which the comment should be added. +
-Allowed values are `REVISION` and `PARENT`. +
-If not set, the default is `REVISION`.
-|`line`        |optional|
-The number of the line for which the comment should be added. +
-`0` if it is a file comment. +
-If neither line nor range is set, a file comment is added. +
-If range is set, this value is ignored in favor of the `end_line` of the range.
-|`range`       |optional|
-The range of the comment as a link:#comment-range[CommentRange]
-entity.
-|`in_reply_to` |optional|
-The URL encoded UUID of the comment to which this comment is a reply.
-|`message`     |optional|
-The comment message.
-|`robot_id`       ||The ID of the robot that generated this comment.
-|`robot_run_id`   ||An ID of the run of the robot.
-|`url`            |optional|URL to more information.
-|`properties`     |optional|Robot specific properties as map that maps arbitrary
-keys to values.
-|===========================
-
 [[rule-input]]
 === RuleInput
 The `RuleInput` entity contains information to test a Prolog rule.
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index 73cd1f1..c88e48c 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -2047,10 +2047,10 @@
 configuration parameter] that controls whether the mergeability bit in
 link:rest-api-changes.html#change-info[ChangeInfo] will never be set and if the
 bit is indexed.
-|`enable_robot_comments`|not set if `false`|
-link:config-gerrit.html#change.enableRobotComments[Are robot comments enabled?].
 |`conflicts_predicate_enabled`|not set if `false`|
 link:config-gerrit.html#change.conflictsPredicateEnabled[Are conflicts enabled?].
+|`allow_markdown_base64_images_in_comments`|not set if `false`|
+link:config-gerrit.html#change.allowMarkdownBase64ImagesInComments[Are markdown base64 images in comments allowed?].
 |=============================
 
 [[change-index-config-info]]
@@ -2546,6 +2546,9 @@
 The list of submit requirement names that should be displayed as separate
 columns in the dashboard. If empty, the default is to display all submit
 requirements that are applicable for changes appearing in the dashboard.
+|`dashboard_show_all_labels` |not set if `false`|
+Whether to show all labels in the dashboard, even if they are not submit
+requirements.
 |`metadata`                ||
 Optional server metadata as a list of link:#metadata-info[MetadataInfo]
 entities. If and which metadata is provided depends on the Gerrit setup.
diff --git a/java/com/google/gerrit/acceptance/testsuite/change/ChangeOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/change/ChangeOperationsImpl.java
index a4f77a1..2d68974 100644
--- a/java/com/google/gerrit/acceptance/testsuite/change/ChangeOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/change/ChangeOperationsImpl.java
@@ -471,7 +471,7 @@
 
   private ChangeInserter getChangeInserter(Change.Id changeId, String refName, ObjectId commitId) {
     ChangeInserter inserter = changeInserterFactory.create(changeId, commitId, refName);
-    inserter.setMessage(String.format("Uploaded patchset %d.", inserter.getPatchSetId().get()));
+    inserter.setMessage(String.format("Uploaded patch set %d.", inserter.getPatchSetId().get()));
     return inserter;
   }
 
@@ -667,7 +667,7 @@
       PatchSetInserter patchSetInserter =
           patchsetInserterFactory.create(changeNotes, patchsetId, newPatchsetCommit);
       patchSetInserter.setCheckAddPatchSetPermission(false);
-      patchSetInserter.setMessage(String.format("Uploaded patchset %d.", patchsetId.get()));
+      patchSetInserter.setMessage(String.format("Uploaded patch set %d.", patchsetId.get()));
       return patchSetInserter;
     }
 
diff --git a/java/com/google/gerrit/entities/BooleanProjectConfig.java b/java/com/google/gerrit/entities/BooleanProjectConfig.java
index 09f63d4..52afc07 100644
--- a/java/com/google/gerrit/entities/BooleanProjectConfig.java
+++ b/java/com/google/gerrit/entities/BooleanProjectConfig.java
@@ -68,4 +68,10 @@
   public String getName() {
     return name;
   }
+
+  public String format() {
+    return getSubSection() != null
+        ? String.format("%s.%s.%s", getSection(), getSubSection(), getName())
+        : String.format("%s.%s", getSection(), getName());
+  }
 }
diff --git a/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java b/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java
index 80bf130..dd4549f 100644
--- a/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java
+++ b/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java
@@ -23,4 +23,5 @@
   public String mergeabilityComputationBehavior;
   public Boolean enableRobotComments;
   public Boolean conflictsPredicateEnabled;
+  public Boolean allowMarkdownBase64ImagesInComments;
 }
diff --git a/java/com/google/gerrit/extensions/common/FileInfo.java b/java/com/google/gerrit/extensions/common/FileInfo.java
index 9526fbb..29a6d4f 100644
--- a/java/com/google/gerrit/extensions/common/FileInfo.java
+++ b/java/com/google/gerrit/extensions/common/FileInfo.java
@@ -20,6 +20,8 @@
   public Character status;
   public Integer oldMode;
   public Integer newMode;
+  public String oldSha;
+  public String newSha;
   public Boolean binary;
   public String oldPath;
   public Integer linesInserted;
@@ -32,6 +34,10 @@
     if (o instanceof FileInfo) {
       FileInfo fileInfo = (FileInfo) o;
       return Objects.equals(status, fileInfo.status)
+          && Objects.equals(oldMode, fileInfo.oldMode)
+          && Objects.equals(newMode, fileInfo.newMode)
+          && Objects.equals(oldSha, fileInfo.oldSha)
+          && Objects.equals(newSha, fileInfo.newSha)
           && Objects.equals(binary, fileInfo.binary)
           && Objects.equals(oldPath, fileInfo.oldPath)
           && Objects.equals(linesInserted, fileInfo.linesInserted)
@@ -52,6 +58,14 @@
     return "FileInfo{"
         + "status="
         + status
+        + ", oldMode="
+        + oldMode
+        + ", newMode="
+        + oldMode
+        + ", oldSha="
+        + oldSha
+        + ", newSha="
+        + oldSha
         + ", binary="
         + binary
         + ", oldPath="
diff --git a/java/com/google/gerrit/extensions/common/ServerInfo.java b/java/com/google/gerrit/extensions/common/ServerInfo.java
index 0a3b6ee..b378a93 100644
--- a/java/com/google/gerrit/extensions/common/ServerInfo.java
+++ b/java/com/google/gerrit/extensions/common/ServerInfo.java
@@ -31,6 +31,7 @@
   public ReceiveInfo receive;
   public String defaultTheme;
   public List<String> submitRequirementDashboardColumns;
+  public Boolean dashboardShowAllLabels;
 
   /** Server metadata populated by plugins. */
   public List<MetadataInfo> metadata;
diff --git a/java/com/google/gerrit/pgm/Reindex.java b/java/com/google/gerrit/pgm/Reindex.java
index c5e133f..7c0f258 100644
--- a/java/com/google/gerrit/pgm/Reindex.java
+++ b/java/com/google/gerrit/pgm/Reindex.java
@@ -58,6 +58,7 @@
 import com.google.inject.Key;
 import com.google.inject.Module;
 import com.google.inject.multibindings.OptionalBinder;
+import com.google.inject.name.Named;
 import java.io.StringWriter;
 import java.io.Writer;
 import java.lang.reflect.InvocationTargetException;
@@ -68,6 +69,7 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 import org.eclipse.jgit.lib.Config;
@@ -100,6 +102,12 @@
   @Option(name = "--build-bloom-filter", usage = "Build bloom filter for H2 disk caches.")
   private boolean buildBloomFilter;
 
+  @Option(
+      name = "--read-only-disk-caches",
+      aliases = {"--ro-disk-caches"},
+      usage = "Don't update H2 disk caches.")
+  private boolean readOnlyDiskCaches;
+
   private Boolean reuseExistingDocumentsOption;
 
   private Injector dbInjector;
@@ -111,6 +119,9 @@
   @Inject private Collection<IndexDefinition<?, ?, ?>> indexDefs;
   @Inject private DynamicMap<Cache<?, ?>> cacheMap;
 
+  @Inject
+  private @Named("DiskCacheReadOnly") AtomicBoolean isDiskCacheReadOnly;
+
   @Option(name = "--reuse", usage = "Reindex only when existing index entry is stale")
   public void setReuseExistingDocuments(boolean value) {
     reuseExistingDocumentsOption = value;
@@ -139,6 +150,7 @@
 
     sysInjector.injectMembers(this);
     checkIndicesOption();
+    isDiskCacheReadOnly.set(readOnlyDiskCaches);
 
     try {
       boolean ok = list ? list() : reindex();
diff --git a/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java b/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
index 4eded88..039a33e 100644
--- a/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
+++ b/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
@@ -36,6 +36,7 @@
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
+import com.google.inject.name.Named;
 import java.nio.file.Path;
 import java.time.Duration;
 import java.util.ArrayList;
@@ -46,6 +47,7 @@
 import java.util.concurrent.Future;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import org.eclipse.jgit.lib.Config;
 
 /**
@@ -84,6 +86,7 @@
   private final Set<CacheOptions> options;
   private final boolean pruneOnStartup;
   private final Schedule schedule;
+  private final AtomicBoolean isDiskCacheReadOnly;
 
   @Inject
   H2CacheFactory(
@@ -93,7 +96,8 @@
       @Nullable @CacheCleanupExecutor ScheduledExecutorService cleanupExecutor,
       @Nullable @CacheStoreExecutor ExecutorService storeExecutor,
       @Nullable @CacheDir Path cacheDir,
-      Set<CacheOptions> options) {
+      Set<CacheOptions> options,
+      @Named("DiskCacheReadOnly") AtomicBoolean isDiskCacheReadOnly) {
     super(memCacheFactory, cfg, cacheDir);
     h2CacheSize = cfg.getLong("cache", null, "h2CacheSize", -1);
     h2AutoServer = cfg.getBoolean("cache", null, "h2AutoServer", false);
@@ -107,6 +111,7 @@
     this.executor = storeExecutor;
     this.cleanup = cleanupExecutor;
     this.options = options;
+    this.isDiskCacheReadOnly = isDiskCacheReadOnly;
   }
 
   @Override
@@ -245,7 +250,8 @@
         expireAfterWrite,
         refreshAfterWrite,
         options.contains(CacheOptions.BUILD_BLOOM_FILTER),
-        options.contains(CacheOptions.TRACK_LAST_ACCESS));
+        options.contains(CacheOptions.TRACK_LAST_ACCESS),
+        isDiskCacheReadOnly);
   }
 
   private boolean has(String name, String var) {
diff --git a/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java b/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
index 376ee90..f66d9cf 100644
--- a/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
+++ b/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
@@ -55,6 +55,7 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
 /**
@@ -342,6 +343,7 @@
     private final AtomicLong missCount = new AtomicLong();
     private final ConcurrentBloomFilter<K> bloomFilter;
     private boolean trackLastAccess;
+    private final AtomicBoolean isDiskCacheReadOnly;
 
     SqlStore(
         String jdbcUrl,
@@ -354,7 +356,8 @@
         @Nullable Duration expireAfterWrite,
         @Nullable Duration refreshAfterWrite,
         boolean buildBloomFilter,
-        boolean trackLastAccess) {
+        boolean trackLastAccess,
+        AtomicBoolean isDiskCacheReadOnly) {
       this.url = jdbcUrl;
       this.keyType = createKeyType(keyType, keySerializer);
       this.valueSerializer = valueSerializer;
@@ -363,6 +366,7 @@
       this.expireAfterWrite = expireAfterWrite;
       this.refreshAfterWrite = refreshAfterWrite;
       this.trackLastAccess = trackLastAccess;
+      this.isDiskCacheReadOnly = isDiskCacheReadOnly;
 
       int cores = Runtime.getRuntime().availableProcessors();
       int keep = Math.min(cores, 16);
@@ -524,6 +528,10 @@
     }
 
     private void touch(SqlHandle c, K key) throws IOException, SQLException {
+      if (isDiskCacheReadOnly.get()) {
+        return;
+      }
+
       if (c.touch == null) {
         c.touch = c.conn.prepareStatement("UPDATE data SET accessed=? WHERE k=? AND version=?");
       }
@@ -538,6 +546,9 @@
     }
 
     void put(K key, ValueHolder<V> holder) {
+      if (isDiskCacheReadOnly.get()) {
+        return;
+      }
       if (holder.clean) {
         return;
       }
@@ -572,6 +583,9 @@
     }
 
     void invalidate(K key) {
+      if (isDiskCacheReadOnly.get()) {
+        return;
+      }
       SqlHandle c = null;
       try {
         c = acquire();
@@ -599,6 +613,9 @@
     }
 
     void invalidateAll() {
+      if (isDiskCacheReadOnly.get()) {
+        return;
+      }
       SqlHandle c = null;
       try {
         c = acquire();
@@ -615,6 +632,9 @@
     }
 
     synchronized void prune(Cache<K, ?> mem) {
+      if (isDiskCacheReadOnly.get()) {
+        return;
+      }
       SqlHandle c = null;
       try {
         c = acquire();
diff --git a/java/com/google/gerrit/server/cache/h2/H2CacheModule.java b/java/com/google/gerrit/server/cache/h2/H2CacheModule.java
index 68017f4..baf08e6 100644
--- a/java/com/google/gerrit/server/cache/h2/H2CacheModule.java
+++ b/java/com/google/gerrit/server/cache/h2/H2CacheModule.java
@@ -28,6 +28,7 @@
 import com.google.gerrit.server.logging.LoggingContextAwareExecutorService;
 import com.google.inject.Provides;
 import com.google.inject.Singleton;
+import com.google.inject.name.Names;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -36,6 +37,7 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
 import org.eclipse.jgit.lib.Config;
 
 @ModuleImpl(name = CacheModule.PERSISTENT_MODULE)
@@ -54,6 +56,9 @@
 
   @Override
   protected void configure() {
+    bind(AtomicBoolean.class)
+        .annotatedWith(Names.named("DiskCacheReadOnly"))
+        .toInstance(new AtomicBoolean(false));
     bind(PersistentCacheFactory.class).to(H2CacheFactory.class);
     listener().to(H2CacheFactory.class);
   }
diff --git a/java/com/google/gerrit/server/change/FileInfoJsonImpl.java b/java/com/google/gerrit/server/change/FileInfoJsonImpl.java
index d9c30d7..cda6191 100644
--- a/java/com/google/gerrit/server/change/FileInfoJsonImpl.java
+++ b/java/com/google/gerrit/server/change/FileInfoJsonImpl.java
@@ -112,6 +112,9 @@
           fileDiff.newMode().isPresent() && !fileDiff.newMode().get().equals(Patch.FileMode.MISSING)
               ? fileDiff.newMode().get().getMode()
               : null;
+      fileDiff.oldSha().ifPresent(sha -> fileInfo.oldSha = sha.name());
+      fileDiff.newSha().ifPresent(sha -> fileInfo.newSha = sha.name());
+
       if (fileDiff.patchType().get() == Patch.PatchType.BINARY) {
         fileInfo.binary = true;
       } else {
diff --git a/java/com/google/gerrit/server/change/ReviewerModifier.java b/java/com/google/gerrit/server/change/ReviewerModifier.java
index 6d454ae..6cc2f87 100644
--- a/java/com/google/gerrit/server/change/ReviewerModifier.java
+++ b/java/com/google/gerrit/server/change/ReviewerModifier.java
@@ -57,6 +57,10 @@
 import com.google.gerrit.server.account.AccountLoader;
 import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.account.GroupMembers;
+import com.google.gerrit.server.change.ReviewerModifier.FailureBehavior;
+import com.google.gerrit.server.change.ReviewerModifier.InternalReviewerInput;
+import com.google.gerrit.server.change.ReviewerModifier.ReviewerModification;
+import com.google.gerrit.server.change.ReviewerModifier.ReviewerModificationList;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.group.GroupResolver;
 import com.google.gerrit.server.group.SystemGroupBackend;
@@ -287,7 +291,15 @@
         reviewerUser =
             accountResolver.resolveIncludeInactiveIgnoreVisibility(input.reviewer).asUniqueUser();
       } else {
-        reviewerUser = accountResolver.resolveIncludeInactive(input.reviewer).asUniqueUser();
+        // First search only active accounts to see if only one unique account is returned
+        AccountResolver.Result accountResolverResult = accountResolver.resolve(input.reviewer);
+
+        if (accountResolverResult.asList().isEmpty()) {
+          // Fallback to searching inactive account
+          accountResolverResult = accountResolver.resolveIncludeInactive(input.reviewer);
+        }
+
+        reviewerUser = accountResolverResult.asUniqueUser();
       }
       if (input.reviewer.equalsIgnoreCase(reviewerUser.getName())
           || input.reviewer.equals(String.valueOf(reviewerUser.getAccountId()))) {
diff --git a/java/com/google/gerrit/server/config/DefaultBooleanProjectConfig.java b/java/com/google/gerrit/server/config/DefaultBooleanProjectConfig.java
new file mode 100644
index 0000000..3e1cb69
--- /dev/null
+++ b/java/com/google/gerrit/server/config/DefaultBooleanProjectConfig.java
@@ -0,0 +1,114 @@
+// Copyright (C) 2025 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.config;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Enums;
+import com.google.common.base.Splitter;
+import com.google.gerrit.common.Nullable;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+
+/** Default values for {@link com.google.gerrit.entities.BooleanProjectConfig}'s. */
+@AutoValue
+public abstract class DefaultBooleanProjectConfig {
+  public enum Value {
+    /**
+     * The boolean config is {@code false} by default. Projects may override the default value in
+     * their {@code project.config}.
+     */
+    FALSE,
+    /**
+     * The boolean config is {@code true} by default. Projects may override the default value in
+     * their {@code project.config}.
+     */
+    TRUE,
+    /**
+     * The boolean config is {@code true} for all projects. Projects cannot override the default
+     * value in their {@code project.config} (existing configurations for this parameter on project
+     * level are ignored).
+     */
+    FORCED;
+  }
+
+  /** Name of the section in {@code project.config} that defines the boolean project config. */
+  public abstract String section();
+
+  /**
+   * Name of the subsection in {@code project.config} that defines the boolean project config. May
+   * be unset if the boolean project config doesn't have a subsection.
+   */
+  public abstract Optional<String> subSection();
+
+  /** Name of the boolean project config in {@code project.config}. */
+  public abstract String name();
+
+  /** The default value for the boolean project config. */
+  public abstract Value defaultValue();
+
+  /**
+   * Tries to parse a string representation of a default boolean project config in the format {code
+   * <section>.<name>=<defaultValue>} or {code <section>.<subSection>.<name>=<defaultValue>}.
+   *
+   * @param s the string representation of the default boolean project config that should be parsed
+   * @return the parsed default boolean project config, or {@code Optional#empty()} if parsing the
+   *     given string was not successful
+   */
+  public static Optional<DefaultBooleanProjectConfig> tryParse(String s) {
+    if (s == null) {
+      return Optional.empty();
+    }
+
+    // Split '<key>=<defaultValue>'.
+    List<String> keyValueList = Splitter.on('=').splitToList(s);
+    if (keyValueList.size() != 2) {
+      return Optional.empty();
+    }
+    String key = keyValueList.get(0);
+    String defaultValue = keyValueList.get(1);
+
+    // Split '<section>.<name>' or '<section>.<subSection>.<name>'.
+    List<String> keyList = Splitter.on('.').splitToList(key);
+    if (keyList.size() != 2 && keyList.size() != 3) {
+      return Optional.empty();
+    }
+    String section = keyList.get(0);
+    String subSection = keyList.size() == 3 ? keyList.get(1) : null;
+    String name = keyList.size() == 3 ? keyList.get(2) : keyList.get(1);
+
+    // Check that none of the parsed parts is empty.
+    if (section.length() == 0
+        || (subSection != null && subSection.length() == 0)
+        || name.length() == 0) {
+      return Optional.empty();
+    }
+
+    // Parse the default value.
+    com.google.common.base.Optional<Value> defaultValueAsEnum =
+        Enums.getIfPresent(Value.class, defaultValue.toUpperCase(Locale.US));
+    if (!defaultValueAsEnum.isPresent()) {
+      return Optional.empty();
+    }
+
+    return Optional.of(create(section, subSection, name, defaultValueAsEnum.get()));
+  }
+
+  private static DefaultBooleanProjectConfig create(
+      String section, @Nullable String subSection, String name, Value defaultValue) {
+    return new AutoValue_DefaultBooleanProjectConfig(
+        section, Optional.ofNullable(subSection), name, defaultValue);
+  }
+}
diff --git a/java/com/google/gerrit/server/config/RepositoryConfig.java b/java/com/google/gerrit/server/config/RepositoryConfig.java
index c008f63..d6701c7 100644
--- a/java/com/google/gerrit/server/config/RepositoryConfig.java
+++ b/java/com/google/gerrit/server/config/RepositoryConfig.java
@@ -18,21 +18,28 @@
 import static java.util.Comparator.comparing;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.common.Nullable;
+import com.google.gerrit.entities.BooleanProjectConfig;
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.client.SubmitType;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Locale;
 import java.util.Objects;
+import java.util.Optional;
 import org.eclipse.jgit.lib.Config;
 
 @Singleton
 public class RepositoryConfig {
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   static final String SECTION_NAME = "repository";
   static final String OWNER_GROUP_NAME = "ownerGroup";
+  static final String DEFAULT_CONFIG_NAME = "defaultConfig";
   static final String DEFAULT_SUBMIT_TYPE_NAME = "defaultSubmitType";
   static final String BASE_PATH_NAME = "basePath";
 
@@ -45,6 +52,56 @@
     this.cfg = cfg;
   }
 
+  /**
+   * Gets the default value that is configured for the given boolean project config that matches the
+   * given project.
+   *
+   * <p>If no default value is configured, {@link DefaultBooleanProjectConfig.Value#FALSE} is
+   * returned.
+   */
+  public DefaultBooleanProjectConfig.Value getDefault(
+      Project.NameKey project, BooleanProjectConfig booleanProjectConfig) {
+    Optional<DefaultBooleanProjectConfig.Value> configuredDefault =
+        Arrays.stream(
+                cfg.getStringList(SECTION_NAME, findSubSection(project.get()), DEFAULT_CONFIG_NAME))
+            .map(DefaultBooleanProjectConfig::tryParse)
+            .filter(Optional::isPresent)
+            .map(Optional::get)
+            .filter(
+                defaultBooleanProjectConfig ->
+                    defaultBooleanProjectConfig.section().equals(booleanProjectConfig.getSection())
+                        && defaultBooleanProjectConfig
+                            .subSection()
+                            .equals(Optional.ofNullable(booleanProjectConfig.getSubSection()))
+                        && defaultBooleanProjectConfig
+                            .name()
+                            .equals(booleanProjectConfig.getName()))
+            .findFirst()
+            .map(DefaultBooleanProjectConfig::defaultValue);
+
+    if (configuredDefault.isPresent()) {
+      if (configuredDefault.get().equals(DefaultBooleanProjectConfig.Value.FORCED)) {
+        logger.atFine().log(
+            "enforcing configured default %s=%s for project %s (settings for %s on project-level"
+                + " are ignored)",
+            booleanProjectConfig.format(),
+            configuredDefault.get().name().toLowerCase(Locale.US),
+            project,
+            booleanProjectConfig.format());
+      } else {
+        logger.atFine().log(
+            "applying configured default %s=%s for project %s (overrides for %s on project-level do"
+                + " apply)",
+            booleanProjectConfig.format(),
+            configuredDefault.get().name().toLowerCase(Locale.US),
+            project,
+            booleanProjectConfig.format());
+      }
+    }
+
+    return configuredDefault.orElse(DefaultBooleanProjectConfig.Value.FALSE);
+  }
+
   public SubmitType getDefaultSubmitType(Project.NameKey project) {
     return cfg.getEnum(
         SECTION_NAME, findSubSection(project.get()), DEFAULT_SUBMIT_TYPE_NAME, DEFAULT_SUBMIT_TYPE);
diff --git a/java/com/google/gerrit/server/git/validators/CommitValidators.java b/java/com/google/gerrit/server/git/validators/CommitValidators.java
index 392f2ae..72d1d87 100644
--- a/java/com/google/gerrit/server/git/validators/CommitValidators.java
+++ b/java/com/google/gerrit/server/git/validators/CommitValidators.java
@@ -749,20 +749,20 @@
       PersonIdent committer = commit.getCommitterIdent();
       PersonIdent author = commit.getAuthorIdent();
 
-      boolean sboAuthor = false;
-      boolean sboCommitter = false;
-      boolean sboMe = false;
+      boolean signedOffByAuthor = false;
+      boolean signedOffByCommitter = false;
+      boolean signedOffByMe = false;
       for (FooterLine footer : commit.getFooterLines()) {
         if (footer.matches(FooterKey.SIGNED_OFF_BY)) {
           String e = footer.getEmailAddress();
           if (e != null) {
-            sboAuthor |= author.getEmailAddress().equals(e);
-            sboCommitter |= committer.getEmailAddress().equals(e);
-            sboMe |= user.hasEmailAddress(e);
+            signedOffByAuthor |= author.getEmailAddress().equals(e);
+            signedOffByCommitter |= committer.getEmailAddress().equals(e);
+            signedOffByMe |= user.hasEmailAddress(e);
           }
         }
       }
-      if (!sboAuthor && !sboCommitter && !sboMe) {
+      if (!signedOffByAuthor && !signedOffByCommitter && !signedOffByMe) {
         try {
           if (!perm.test(RefPermission.FORGE_COMMITTER)) {
             throw new CommitValidationException(
diff --git a/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java b/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
index 82d7e93..d417fe3 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
@@ -70,6 +70,7 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.util.sha1.SHA1;
 
 /**
  * Cache for the single file diff between two commits for a single file path. This cache adds extra
@@ -97,7 +98,7 @@
         persist(DIFF, FileDiffCacheKey.class, FileDiffOutput.class)
             .maximumWeight(10 << 20)
             .weigher(FileDiffWeigher.class)
-            .version(9)
+            .version(10)
             .keySerializer(FileDiffCacheKey.Serializer.INSTANCE)
             .valueSerializer(FileDiffOutput.Serializer.INSTANCE)
             .loader(FileDiffLoader.class);
@@ -334,6 +335,12 @@
       byte[] rawHdr = getRawHeader(!comparisonType.isAgainstParentOrAutoMerge(), fileName);
       byte[] aContent = aText.getContent();
       byte[] bContent = bText.getContent();
+      SHA1 aContentDigest = SHA1.newInstance();
+      aContentDigest.update(aContent);
+      ObjectId aSha = ObjectId.fromRaw(aContentDigest.digest());
+      SHA1 bContentDigest = SHA1.newInstance();
+      bContentDigest.update(bContent);
+      ObjectId bSha = ObjectId.fromRaw(aContentDigest.digest());
       long size = bContent.length;
       long sizeDelta = size - aContent.length;
       RawText aRawText = new RawText(aContent);
@@ -348,6 +355,8 @@
           .comparisonType(comparisonType)
           .oldPath(FileHeaderUtil.getOldPath(fileHeader))
           .newPath(FileHeaderUtil.getNewPath(fileHeader))
+          .oldSha(Optional.of(aSha))
+          .newSha(Optional.of(bSha))
           .changeType(changeType)
           .patchType(Optional.of(FileHeaderUtil.getPatchType(fileHeader)))
           .headerLines(FileHeaderUtil.getHeaderLines(fileHeader))
@@ -415,22 +424,20 @@
         RevTree aTree = oldTreeId.equals(ObjectId.zeroId()) ? null : rw.parseTree(oldTreeId);
         RevTree bTree = rw.parseTree(allDiffs.mainDiff().gitKey().newTree());
 
-        Long oldSize =
+        FileSizeEvaluator aEvaluator = new FileSizeEvaluator(reader, aTree);
+        ObjectId oldSha =
             aTree != null && mainGitDiff.oldMode().isPresent() && mainGitDiff.oldPath().isPresent()
-                ? new FileSizeEvaluator(reader, aTree)
-                    .compute(
-                        mainGitDiff.oldId(),
-                        mainGitDiff.oldMode().get(),
-                        mainGitDiff.oldPath().get())
-                : 0;
-        Long newSize =
+                ? aEvaluator.getFileObjectId(
+                    mainGitDiff.oldId(), mainGitDiff.oldMode().get(), mainGitDiff.oldPath().get())
+                : ObjectId.zeroId();
+        Long oldSize = aEvaluator.compute(oldSha);
+        FileSizeEvaluator bEvaluator = new FileSizeEvaluator(reader, bTree);
+        ObjectId newSha =
             mainGitDiff.newMode().isPresent() && mainGitDiff.newPath().isPresent()
-                ? new FileSizeEvaluator(reader, bTree)
-                    .compute(
-                        mainGitDiff.newId(),
-                        mainGitDiff.newMode().get(),
-                        mainGitDiff.newPath().get())
-                : 0;
+                ? bEvaluator.getFileObjectId(
+                    mainGitDiff.newId(), mainGitDiff.newMode().get(), mainGitDiff.newPath().get())
+                : ObjectId.zeroId();
+        Long newSize = bEvaluator.compute(newSha);
 
         ObjectId oldCommit = augmentedKey.key().oldCommit();
         ObjectId newCommit = augmentedKey.key().newCommit();
@@ -445,6 +452,8 @@
                 .newPath(mainGitDiff.newPath())
                 .oldMode(mainGitDiff.oldMode())
                 .newMode(mainGitDiff.newMode())
+                .oldSha(!oldSha.equals(ObjectId.zeroId()) ? Optional.of(oldSha) : Optional.empty())
+                .newSha(!newSha.equals(ObjectId.zeroId()) ? Optional.of(newSha) : Optional.empty())
                 .headerLines(FileHeaderUtil.getHeaderLines(mainGitDiff.fileHeader()))
                 .edits(asTaggedEdits(mainGitDiff.edits(), rebaseEdits))
                 .size(newSize)
diff --git a/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java b/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
index b7cd5e4..dd6b8d9 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
@@ -38,7 +38,7 @@
 /** File diff for a single file path. Produced as output of the {@link FileDiffCache}. */
 @AutoValue
 public abstract class FileDiffOutput implements Serializable {
-  private static final long serialVersionUID = 1L;
+  private static final long serialVersionUID = 2L;
 
   /**
    * The 20 bytes SHA-1 object ID of the old git commit used in the diff, or {@link
@@ -80,6 +80,20 @@
    */
   public abstract Optional<Patch.FileMode> newMode();
 
+  /**
+   * The SHA-1 of the old file at the old git tree diff identified by {@link #oldCommitId()} ()}.
+   *
+   * <p>Not populated if diffing was not performed (ie. error/timeout) or if the file is added.
+   */
+  public abstract Optional<ObjectId> oldSha();
+
+  /**
+   * The SHA-1 of the new file at the new git tree diff identified by {@link #newCommitId()} ()}.
+   *
+   * <p>Not populated if diffing was not performed (ie. error/timeout) or if the file is deleted.
+   */
+  public abstract Optional<ObjectId> newSha();
+
   /** The change type of the underlying file, e.g. added, deleted, renamed, etc... */
   public abstract Patch.ChangeType changeType();
 
@@ -223,6 +237,10 @@
 
     public abstract Builder newMode(Optional<Patch.FileMode> newMode);
 
+    public abstract Builder oldSha(Optional<ObjectId> oldSha);
+
+    public abstract Builder newSha(Optional<ObjectId> newSha);
+
     public abstract Builder changeType(ChangeType value);
 
     public abstract Builder patchType(Optional<PatchType> value);
@@ -264,6 +282,12 @@
     private static final FieldDescriptor NEW_MODE_DESCRIPTOR =
         FileDiffOutputProto.getDescriptor().findFieldByNumber(14);
 
+    private static final FieldDescriptor OLD_SHA_DESCRIPTOR =
+        FileDiffOutputProto.getDescriptor().findFieldByNumber(15);
+
+    private static final FieldDescriptor NEW_SHA_DESCRIPTOR =
+        FileDiffOutputProto.getDescriptor().findFieldByNumber(16);
+
     @Override
     public byte[] serialize(FileDiffOutput fileDiff) {
       ObjectIdConverter idConverter = ObjectIdConverter.create();
@@ -315,6 +339,14 @@
         builder.setNewMode(FILE_MODE_CONVERTER.reverse().convert(fileDiff.newMode().get()));
       }
 
+      if (fileDiff.oldSha().isPresent()) {
+        builder.setOldSha(idConverter.toByteString(fileDiff.oldSha().get()));
+      }
+
+      if (fileDiff.newSha().isPresent()) {
+        builder.setNewSha(idConverter.toByteString(fileDiff.newSha().get()));
+      }
+
       return Protos.toByteArray(builder.build());
     }
 
@@ -362,6 +394,12 @@
       if (proto.hasField(NEW_MODE_DESCRIPTOR)) {
         builder.newMode(Optional.of(FILE_MODE_CONVERTER.convert(proto.getNewMode())));
       }
+      if (proto.hasField(OLD_SHA_DESCRIPTOR)) {
+        builder.oldSha(Optional.of(idConverter.fromByteString(proto.getOldSha())));
+      }
+      if (proto.hasField(NEW_SHA_DESCRIPTOR)) {
+        builder.newSha(Optional.of(idConverter.fromByteString(proto.getNewSha())));
+      }
       return builder.build();
     }
   }
diff --git a/java/com/google/gerrit/server/patch/filediff/FileSizeEvaluator.java b/java/com/google/gerrit/server/patch/filediff/FileSizeEvaluator.java
index e2c1bc5..77c022e 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileSizeEvaluator.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileSizeEvaluator.java
@@ -41,15 +41,22 @@
   }
 
   /**
+   * Computes the file ObjectId (SHA-1) identified by the {@code path} parameter at the given git
+   * tree identified by {@code gitTreeId}.
+   */
+  ObjectId getFileObjectId(AbbreviatedObjectId gitTreeId, Patch.FileMode mode, String path)
+      throws IOException {
+    if (!isBlob(mode)) {
+      return ObjectId.zeroId();
+    }
+    return toObjectId(reader, gitTreeId).orElseGet(() -> lookupObjectId(reader, path, tree));
+  }
+
+  /**
    * Computes the file size identified by the {@code path} parameter at the given git tree
    * identified by {@code gitTreeId}.
    */
-  long compute(AbbreviatedObjectId gitTreeId, Patch.FileMode mode, String path) throws IOException {
-    if (!isBlob(mode)) {
-      return 0;
-    }
-    ObjectId fileId =
-        toObjectId(reader, gitTreeId).orElseGet(() -> lookupObjectId(reader, path, tree));
+  long compute(ObjectId fileId) throws IOException {
     if (ObjectId.zeroId().equals(fileId)) {
       return 0;
     }
diff --git a/java/com/google/gerrit/server/project/ProjectState.java b/java/com/google/gerrit/server/project/ProjectState.java
index dd5e72f..4c5e6ff 100644
--- a/java/com/google/gerrit/server/project/ProjectState.java
+++ b/java/com/google/gerrit/server/project/ProjectState.java
@@ -45,7 +45,9 @@
 import com.google.gerrit.server.account.CapabilityCollection;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.DefaultBooleanProjectConfig;
 import com.google.gerrit.server.config.PluginConfig;
+import com.google.gerrit.server.config.RepositoryConfig;
 import com.google.gerrit.server.git.TransferConfig;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.inject.Inject;
@@ -76,6 +78,7 @@
 
   private final boolean isAllProjects;
   private final boolean isAllUsers;
+  private final RepositoryConfig repositoryConfig;
   private final AllProjectsName allProjectsName;
   private final ProjectCache projectCache;
   private final List<CommentLinkInfo> commentLinks;
@@ -93,6 +96,7 @@
 
   @Inject
   public ProjectState(
+      RepositoryConfig repositoryConfig,
       ProjectCache projectCache,
       AllProjectsName allProjectsName,
       AllUsersName allUsersName,
@@ -100,6 +104,7 @@
       CapabilityCollection.Factory limitsFactory,
       TransferConfig transferConfig,
       @Assisted CachedProjectConfig cachedProjectConfig) {
+    this.repositoryConfig = repositoryConfig;
     this.projectCache = projectCache;
     this.isAllProjects = cachedProjectConfig.getProject().getNameKey().equals(allProjectsName);
     this.isAllUsers = cachedProjectConfig.getProject().getNameKey().equals(allUsersName);
@@ -370,6 +375,12 @@
   }
 
   public boolean is(BooleanProjectConfig config) {
+    DefaultBooleanProjectConfig.Value defaultValue =
+        repositoryConfig.getDefault(getNameKey(), config);
+    if (DefaultBooleanProjectConfig.Value.FORCED.equals(defaultValue)) {
+      return true;
+    }
+
     for (ProjectState s : tree()) {
       switch (s.getProject().getBooleanConfig(config)) {
         case TRUE:
@@ -381,7 +392,11 @@
           continue;
       }
     }
-    return false;
+
+    return switch (defaultValue) {
+      case TRUE, FORCED -> true;
+      case FALSE -> false;
+    };
   }
 
   /** Get all submit requirements for a project, including those from parent projects. */
diff --git a/java/com/google/gerrit/server/restapi/change/Restore.java b/java/com/google/gerrit/server/restapi/change/Restore.java
index d33f8df..8faa6a1 100644
--- a/java/com/google/gerrit/server/restapi/change/Restore.java
+++ b/java/com/google/gerrit/server/restapi/change/Restore.java
@@ -102,6 +102,12 @@
         .orElseThrow(illegalState(rsrc.getProject()))
         .checkStatePermitsWrite();
 
+    if (input == null) {
+      // https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#restore-change
+      // input can be null if no review comments are set
+      input = new RestoreInput();
+    }
+
     Op op = new Op(input);
     try (RefUpdateContext ctx = RefUpdateContext.open(CHANGE_MODIFICATION)) {
       try (BatchUpdate u =
diff --git a/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java b/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
index 81fa387..2adb9fc 100644
--- a/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
+++ b/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
@@ -52,6 +52,7 @@
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
@@ -252,9 +253,12 @@
     }
     Account account = accountState.account();
     if (account.isActive()) {
-      if (Strings.isNullOrEmpty(query)
-          || (account.fullName() != null && account.fullName().startsWith(query))
-          || (account.preferredEmail() != null && account.preferredEmail().startsWith(query))) {
+      String lowerCaseQuery = Strings.nullToEmpty(query).toLowerCase(Locale.US);
+      if (Strings.isNullOrEmpty(lowerCaseQuery)
+          || (account.fullName() != null
+              && account.fullName().toLowerCase(Locale.US).startsWith(lowerCaseQuery))
+          || (account.preferredEmail() != null
+              && account.preferredEmail().toLowerCase(Locale.US).startsWith(lowerCaseQuery))) {
         return true;
       }
     }
diff --git a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
index 0b254ce..b4140d3 100644
--- a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
+++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
@@ -164,6 +164,7 @@
     info.user = getUserInfo();
     info.receive = getReceiveInfo();
     info.submitRequirementDashboardColumns = getSubmitRequirementDashboardColumns();
+    info.dashboardShowAllLabels = getDashboardShowAllLabels();
     info.metadata = getMetadata();
     return Response.ok(info);
   }
@@ -228,6 +229,8 @@
     info.enableRobotComments = toBoolean(config.getBoolean("change", "enableRobotComments", false));
     info.conflictsPredicateEnabled =
         toBoolean(config.getBoolean("change", "conflictsPredicateEnabled", true));
+    info.allowMarkdownBase64ImagesInComments =
+        toBoolean(config.getBoolean("change", "allowMarkdownBase64ImagesInComments", false));
     return info;
   }
 
@@ -377,6 +380,10 @@
     return Arrays.asList(config.getStringList("dashboard", null, "submitRequirementColumns"));
   }
 
+  private Boolean getDashboardShowAllLabels() {
+    return toBoolean(config.getBoolean("dashboard", null, "showAllLabels", false));
+  }
+
   private ImmutableList<MetadataInfo> getMetadata() {
     ArrayList<MetadataInfo> metadataList = new ArrayList<>();
     serverStateProviders.runEach(
diff --git a/javatests/com/google/gerrit/acceptance/api/project/ProjectConfigIT.java b/javatests/com/google/gerrit/acceptance/api/project/ProjectConfigIT.java
index 9a926ea..6d57632 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/ProjectConfigIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/ProjectConfigIT.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.gerrit.acceptance.GitUtil.fetch;
+import static com.google.gerrit.server.project.ProjectCache.illegalState;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -23,9 +24,11 @@
 import com.google.gerrit.acceptance.ExtensionRegistry;
 import com.google.gerrit.acceptance.ExtensionRegistry.Registration;
 import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.config.GerritConfig;
 import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.common.RawInputUtil;
+import com.google.gerrit.entities.BooleanProjectConfig;
 import com.google.gerrit.entities.LabelFunction;
 import com.google.gerrit.entities.RefNames;
 import com.google.gerrit.entities.SubmitRequirement;
@@ -35,6 +38,7 @@
 import com.google.gerrit.extensions.api.projects.ConfigInput;
 import com.google.gerrit.extensions.api.projects.ConfigValue;
 import com.google.gerrit.extensions.client.ChangeStatus;
+import com.google.gerrit.extensions.client.InheritableBoolean;
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.common.ChangeInput;
 import com.google.gerrit.git.ObjectIds;
@@ -1234,6 +1238,136 @@
             + " 'label.Foo.copyCondition'): line 1:0 no viable alternative at input ':'");
   }
 
+  @Test
+  public void falseIsTheDefaultForBooleanProjectConfigIfNoDefaultIsConfigured() throws Exception {
+    assertThat(
+            projectCache
+                .get(project)
+                .orElseThrow(illegalState(project))
+                .is(BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isFalse();
+  }
+
+  @Test
+  @GerritConfig(name = "repository.*.defaultConfig", value = "receive.rejectImplicitMerges=true")
+  public void configureTrueAsDefaultForBooleanProjectConfig() throws Exception {
+    assertThat(
+            projectCache
+                .get(project)
+                .orElseThrow(illegalState(project))
+                .is(BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isTrue();
+
+    // true can be overridden in the project
+    try (ProjectConfigUpdate u = updateProject(project)) {
+      u.getConfig()
+          .updateProject(
+              b ->
+                  b.setBooleanConfig(
+                      BooleanProjectConfig.REJECT_IMPLICIT_MERGES, InheritableBoolean.FALSE));
+      u.save();
+    }
+    assertThat(
+            projectCache
+                .get(project)
+                .orElseThrow(illegalState(project))
+                .is(BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isFalse();
+  }
+
+  @Test
+  @GerritConfig(name = "repository.*.defaultConfig", value = "receive.rejectImplicitMerges=forced")
+  public void configureForcedAsDefaultForBooleanProjectConfig() throws Exception {
+    assertThat(
+            projectCache
+                .get(project)
+                .orElseThrow(illegalState(project))
+                .is(BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isTrue();
+
+    // forced cannot be overridden in the project
+    try (ProjectConfigUpdate u = updateProject(project)) {
+      u.getConfig()
+          .updateProject(
+              b ->
+                  b.setBooleanConfig(
+                      BooleanProjectConfig.REJECT_IMPLICIT_MERGES, InheritableBoolean.FALSE));
+      u.save();
+    }
+    assertThat(
+            projectCache
+                .get(project)
+                .orElseThrow(illegalState(project))
+                .is(BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isTrue();
+  }
+
+  @Test
+  @GerritConfig(name = "repository.*.defaultConfig", value = "receive.rejectImplicitMerges=false")
+  public void configureFalseAsDefaultForBooleanProjectConfig() throws Exception {
+    assertThat(
+            projectCache
+                .get(project)
+                .orElseThrow(illegalState(project))
+                .is(BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isFalse();
+
+    // false can be overridden in the project
+    try (ProjectConfigUpdate u = updateProject(project)) {
+      u.getConfig()
+          .updateProject(
+              b ->
+                  b.setBooleanConfig(
+                      BooleanProjectConfig.REJECT_IMPLICIT_MERGES, InheritableBoolean.TRUE));
+      u.save();
+    }
+    assertThat(
+            projectCache
+                .get(project)
+                .orElseThrow(illegalState(project))
+                .is(BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isTrue();
+  }
+
+  @Test
+  @GerritConfig(name = "repository.*.defaultConfig", value = "receive.rejectImplicitMerges=invalid")
+  public void invalidDefaultForBooleanProjectConfigIsIgnored() throws Exception {
+    assertThat(
+            projectCache
+                .get(project)
+                .orElseThrow(illegalState(project))
+                .is(BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isFalse();
+
+    try (ProjectConfigUpdate u = updateProject(project)) {
+      u.getConfig()
+          .updateProject(
+              b ->
+                  b.setBooleanConfig(
+                      BooleanProjectConfig.REJECT_IMPLICIT_MERGES, InheritableBoolean.TRUE));
+      u.save();
+    }
+    assertThat(
+            projectCache
+                .get(project)
+                .orElseThrow(illegalState(project))
+                .is(BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isTrue();
+  }
+
+  @Test
+  @GerritConfig(
+      name = "repository.*.defaultConfig",
+      values = {"receive.rejectImplicitMerges=true", "receive.rejectImplicitMerges=false"})
+  public void firstConfigureDefaultForBooleanProjectConfigApplies() throws Exception {
+    assertThat(
+            projectCache
+                .get(project)
+                .orElseThrow(illegalState(project))
+                .is(BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isTrue();
+  }
+
   private void testChangingCopyCondition(
       String initialCopyCondition, @Nullable String newCopyCondition) throws Exception {
     testChangingCopyCondition(
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 634906e..c15b4c6 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -597,17 +597,56 @@
     ChangeApi change = gApi.changes().id(project.get() + "~master~" + r.getChangeId());
     CherryPickInput in = new CherryPickInput();
     in.destination = "master";
-    in.message = "it generates a new patch set\n\nChange-Id: " + r.getChangeId();
-    ChangeInfo cherryInfo = change.revision(r.getCommit().name()).cherryPick(in).get();
+    ChangeInfo cherryInfo = change.current().cherryPick(in).get();
     assertThat(cherryInfo.messages).hasSize(2);
-    Iterator<ChangeMessageInfo> cherryIt = cherryInfo.messages.iterator();
+    Iterator<ChangeMessageInfo> cherryMessageIt = cherryInfo.messages.iterator();
     assertThat(cherryInfo.cherryPickOfChange).isEqualTo(change.get()._number);
 
     // Existing change was updated.
     assertThat(cherryInfo._number).isEqualTo(change.get()._number);
+    assertThat(cherryInfo.cherryPickOfChange).isEqualTo(change.get()._number);
     assertThat(cherryInfo.cherryPickOfPatchSet).isEqualTo(1);
-    assertThat(cherryIt.next().message).isEqualTo("Uploaded patch set 1.");
-    assertThat(cherryIt.next().message).isEqualTo("Patch Set 2: Cherry Picked from branch master.");
+    assertThat(cherryMessageIt.next().message).isEqualTo("Uploaded patch set 1.");
+    assertThat(cherryMessageIt.next().message)
+        .isEqualTo("Patch Set 2: Cherry Picked from branch master.");
+  }
+
+  @Test
+  public void restoreOldPatchSetByCherryPickToSameBranch() throws Exception {
+    Change.Id changeId =
+        changeOperations.newChange().project(project).file("a.txt").content("aContent").create();
+    ChangeApi change = gApi.changes().id(project.get(), changeId.get());
+
+    // Amend the change, deleting file a.txt and adding file b.txt.
+    changeOperations
+        .change(changeId)
+        .newPatchset()
+        .file("a.txt")
+        .delete()
+        .file("b.txt")
+        .content("bContent")
+        .create();
+
+    // Restore patch set 1 by cherry-picking it.
+    CherryPickInput in = new CherryPickInput();
+    in.destination = "master";
+    ChangeInfo cherryInfo = change.revision(1).cherryPick(in).get();
+    assertThat(cherryInfo.messages).hasSize(3);
+    Iterator<ChangeMessageInfo> cherryMessageIt = cherryInfo.messages.iterator();
+    assertThat(cherryInfo.cherryPickOfChange).isEqualTo(change.get()._number);
+
+    // Existing change was updated.
+    assertThat(cherryInfo._number).isEqualTo(change.get()._number);
+    assertThat(cherryInfo.cherryPickOfChange).isEqualTo(change.get()._number);
+    assertThat(cherryInfo.cherryPickOfPatchSet).isEqualTo(1);
+    assertThat(cherryMessageIt.next().message).isEqualTo("Uploaded patch set 1.");
+    assertThat(cherryMessageIt.next().message).isEqualTo("Uploaded patch set 2.");
+    assertThat(cherryMessageIt.next().message)
+        .isEqualTo("Patch Set 3: Cherry Picked from branch master.");
+
+    // File a.txt has been restored and b.txt has been removed.
+    Map<String, FileInfo> files = change.current().files();
+    assertThat(files.keySet()).containsExactly("a.txt", COMMIT_MSG);
   }
 
   @Test
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 1bf0f55..3a1acf8 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -108,6 +108,9 @@
 import com.google.gerrit.git.ObjectIds;
 import com.google.gerrit.server.ChangeMessagesUtil;
 import com.google.gerrit.server.PluginPushOption;
+import com.google.gerrit.server.ServerInitiated;
+import com.google.gerrit.server.account.AccountsUpdate;
+import com.google.gerrit.server.account.externalids.ExternalId;
 import com.google.gerrit.server.events.CommitReceivedEvent;
 import com.google.gerrit.server.git.receive.NoteDbPushOption;
 import com.google.gerrit.server.git.receive.PushOptionsValidator;
@@ -122,6 +125,7 @@
 import com.google.gerrit.testing.FakeEmailSender.Message;
 import com.google.gerrit.testing.TestTimeUtil;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -170,6 +174,7 @@
   @Inject private ProjectOperations projectOperations;
   @Inject private RequestScopeOperations requestScopeOperations;
   @Inject private ExtensionRegistry extensionRegistry;
+  @Inject private @ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider;
 
   private static String NEW_CHANGE_INDICATOR = " [NEW]";
   private LabelType patchSetLock;
@@ -825,6 +830,46 @@
   }
 
   @Test
+  public void pushForMasterWithReviewerByEmailWithOneAccountInactive() throws Exception {
+    ConfigInput conf = new ConfigInput();
+    conf.enableReviewerByEmail = InheritableBoolean.TRUE;
+    gApi.projects().name(project.get()).config(conf);
+
+    TestAccount u1 = accountCreator.create("some.user", "some.user@example.com", "Some User", null);
+
+    // Delete the MailTo external ID from u1. We want to create u2 with the same externalId
+    // and without this, the account creation for u2 fails with
+    // com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException
+    ImmutableList<ExternalId> ids =
+        accounts.get(u1.id()).get().externalIds().stream()
+            .filter(id -> id.isScheme(ExternalId.SCHEME_MAILTO))
+            .collect(toImmutableList());
+    for (ExternalId externalId : ids) {
+      accountsUpdateProvider
+          .get()
+          .update("Delete External ID", u1.id(), u -> u.deleteExternalId(externalId));
+    }
+
+    TestAccount u2 =
+        accountCreator.create("some.user2", "some.user@example.com", "Some User2", null);
+
+    gApi.accounts().id(u1.id().get()).setActive(false);
+
+    PushOneCommit.Result r = pushTo("refs/for/master%r=some.user@example.com");
+    r.assertOkStatus();
+
+    ChangeInfo ci = get(r.getChangeId(), DETAILED_LABELS);
+    ImmutableList<AccountInfo> reviewers =
+        firstNonNull(ci.reviewers.get(ReviewerState.REVIEWER), ImmutableList.<AccountInfo>of())
+            .stream()
+            .sorted(comparing((AccountInfo a) -> a.email))
+            .collect(toImmutableList());
+
+    assertThat(reviewers).hasSize(1);
+    assertThat(reviewers.get(0)._accountId).isEqualTo(u2.id().get());
+  }
+
+  @Test
   public void pushForMasterWithReviewerGroup() throws Exception {
     TestAccount user2 = accountCreator.user2();
     String group = name("group");
diff --git a/javatests/com/google/gerrit/acceptance/pgm/AbstractReindexTests.java b/javatests/com/google/gerrit/acceptance/pgm/AbstractReindexTests.java
index 66c4078..8f011f8 100644
--- a/javatests/com/google/gerrit/acceptance/pgm/AbstractReindexTests.java
+++ b/javatests/com/google/gerrit/acceptance/pgm/AbstractReindexTests.java
@@ -74,6 +74,39 @@
   }
 
   @Test
+  public void reindexWithReadOnlyCaches() throws Exception {
+    setUpChange();
+    try (ServerContext ctx = startServer()) {
+      GerritApi gApi = ctx.getInjector().getInstance(GerritApi.class);
+      assertThat(gApi.config().server().caches("diff_summary").get().entries.disk).isEqualTo(1L);
+      gApi.config().server().caches("diff_summary").flush();
+      assertThat(gApi.config().server().caches("diff_summary").get().entries.disk).isNull();
+    }
+
+    runGerrit(
+        "reindex",
+        "-d",
+        sitePaths.site_path.toString(),
+        "--show-stack-trace",
+        "--verbose",
+        "--read-only-disk-caches");
+    assertReady(ChangeSchemaDefinitions.INSTANCE.getLatest().getVersion());
+    assertIndexQueries();
+
+    try (ServerContext ctx = startServer()) {
+      GerritApi gApi = ctx.getInjector().getInstance(GerritApi.class);
+      assertThat(gApi.config().server().caches("diff_summary").get().entries.disk).isNull();
+    }
+
+    runGerrit("reindex", "-d", sitePaths.site_path.toString(), "--show-stack-trace", "--verbose");
+
+    try (ServerContext ctx = startServer()) {
+      GerritApi gApi = ctx.getInjector().getInstance(GerritApi.class);
+      assertThat(gApi.config().server().caches("diff_summary").get().entries.disk).isEqualTo(1L);
+    }
+  }
+
+  @Test
   public void reindexWithSkipExistingDocumentsEnabled() throws Exception {
     updateConfig(config -> config.setBoolean("index", null, "reuseExistingDocuments", true));
     setUpChange();
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java b/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
index f6971c6..e417e54 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
@@ -543,6 +543,52 @@
   }
 
   @Test
+  public void recentReviewerBoostedByCaseInsensitiveMatchInRecommender() throws Exception {
+    requestScopeOperations.setApiUser(admin.id());
+
+    // User B: Also matches the query "john", but is NOT a recent reviewer
+    TestAccount userB_StandardMatch =
+        accountCreator.create(
+            name("userB_Standard"),
+            name("userB_StandardEmail") + "@example.com",
+            "john junior",
+            null);
+    gApi.accounts().id(userB_StandardMatch.id().get()).setActive(true);
+
+    // User A: Will be a recent reviewer. Their name requires a case-insensitive match
+    // by ReviewerRecommender for the query "john".
+    TestAccount userA_RecentReviewer =
+        accountCreator.create(
+            name("userA_Recent"), name("userA_RecentEmail") + "@example.com", "John Senior", null);
+    gApi.accounts().id(userA_RecentReviewer.id().get()).setActive(true);
+
+    // Make userA_RecentReviewer a reviewer on a previous change by admin.
+    String previousChangeId = createChange().getChangeId();
+    ReviewerInput addReviewerAsAdminInput = new ReviewerInput();
+    addReviewerAsAdminInput.reviewer = userA_RecentReviewer.email();
+    gApi.changes().id(previousChangeId).addReviewer(addReviewerAsAdminInput);
+
+    String targetChangeId = createChange().getChangeId();
+
+    // Query for reviewers with "john" (lowercase).
+    List<SuggestedReviewerInfo> suggestions = suggestReviewers(targetChangeId, "john", 5);
+
+    List<Account.Id> suggestedAccountIds =
+        suggestions.stream()
+            .filter(s -> s.account != null)
+            .map(s -> Account.id(s.account._accountId))
+            .collect(toList());
+
+    assertThat(suggestedAccountIds)
+        .containsAtLeast(userA_RecentReviewer.id(), userB_StandardMatch.id());
+
+    int indexOfUserA = suggestedAccountIds.indexOf(userA_RecentReviewer.id());
+    int indexOfUserB = suggestedAccountIds.indexOf(userB_StandardMatch.id());
+
+    assertThat(indexOfUserA).isLessThan(indexOfUserB);
+  }
+
+  @Test
   public void suggestNoServiceAccounts() throws Exception {
     requestScopeOperations.setApiUser(user.id());
     String changeIdReviewed = createChangeFromApi();
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java b/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
index 479baf3..9097e6f 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
@@ -73,7 +73,7 @@
   @GerritConfig(name = "change.updateDelay", value = "50s")
   @GerritConfig(name = "change.disablePrivateChanges", value = "true")
   @GerritConfig(name = "change.enableRobotComments", value = "false")
-
+  @GerritConfig(name = "change.allowMarkdownBase64ImagesInComments", value = "false")
   // download
   @GerritConfig(
       name = "download.archive",
@@ -114,6 +114,7 @@
     assertThat(i.change.updateDelay).isEqualTo(50);
     assertThat(i.change.disablePrivateChanges).isTrue();
     assertThat(i.change.enableRobotComments).isNull();
+    assertThat(i.change.allowMarkdownBase64ImagesInComments).isNull();
 
     // download
     assertThat(i.download.archives).containsExactly("tar", "tbz2", "tgz", "txz");
@@ -205,6 +206,7 @@
 
     // submit requirement columns in dashboard
     assertThat(i.submitRequirementDashboardColumns).isEmpty();
+    assertThat(i.dashboardShowAllLabels).isNull();
   }
 
   @Test
@@ -224,6 +226,13 @@
   }
 
   @Test
+  @GerritConfig(name = "dashboard.showAllLabels", value = "true")
+  public void serverConfigWithDashboardShowAllLabels() throws Exception {
+    ServerInfo i = gApi.config().server().getInfo();
+    assertThat(i.dashboardShowAllLabels).isTrue();
+  }
+
+  @Test
   @GerritConfig(name = "change.mergeabilityComputationBehavior", value = "NEVER")
   public void mergeabilityComputationBehavior_neverCompute() throws Exception {
     ServerInfo i = gApi.config().server().getInfo();
diff --git a/javatests/com/google/gerrit/server/cache/h2/H2CacheTest.java b/javatests/com/google/gerrit/server/cache/h2/H2CacheTest.java
index 508fb3b..8b6ba2a 100644
--- a/javatests/com/google/gerrit/server/cache/h2/H2CacheTest.java
+++ b/javatests/com/google/gerrit/server/cache/h2/H2CacheTest.java
@@ -74,7 +74,8 @@
         expireAfterWrite,
         refreshAfterWrite,
         true,
-        true);
+        true,
+        new AtomicBoolean(false));
   }
 
   @Test
diff --git a/javatests/com/google/gerrit/server/config/DefaultBooleanProjectConfigTest.java b/javatests/com/google/gerrit/server/config/DefaultBooleanProjectConfigTest.java
new file mode 100644
index 0000000..1dfbe2f
--- /dev/null
+++ b/javatests/com/google/gerrit/server/config/DefaultBooleanProjectConfigTest.java
@@ -0,0 +1,137 @@
+// Copyright (C) 2025 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.config;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.common.Nullable;
+import java.util.Optional;
+import org.junit.Test;
+
+/** Unit test for {@link DefaultBooleanProjectConfig}. */
+public class DefaultBooleanProjectConfigTest {
+  @Test
+  public void tryParse() {
+    // assert valid values for key with subsection
+    assertTryParseOk(
+        "section.subsection.name=false",
+        "section",
+        "subsection",
+        "name",
+        DefaultBooleanProjectConfig.Value.FALSE);
+    assertTryParseOk(
+        "section.subsection.name=FALSE",
+        "section",
+        "subsection",
+        "name",
+        DefaultBooleanProjectConfig.Value.FALSE);
+    assertTryParseOk(
+        "section.subsection.name=true",
+        "section",
+        "subsection",
+        "name",
+        DefaultBooleanProjectConfig.Value.TRUE);
+    assertTryParseOk(
+        "section.subsection.name=TRUE",
+        "section",
+        "subsection",
+        "name",
+        DefaultBooleanProjectConfig.Value.TRUE);
+    assertTryParseOk(
+        "section.subsection.name=forced",
+        "section",
+        "subsection",
+        "name",
+        DefaultBooleanProjectConfig.Value.FORCED);
+    assertTryParseOk(
+        "section.subsection.name=FORCED",
+        "section",
+        "subsection",
+        "name",
+        DefaultBooleanProjectConfig.Value.FORCED);
+
+    // assert valid values for key without subsection
+    assertTryParseOk(
+        "section.name=false", "section", null, "name", DefaultBooleanProjectConfig.Value.FALSE);
+    assertTryParseOk(
+        "section.name=FALSE", "section", null, "name", DefaultBooleanProjectConfig.Value.FALSE);
+    assertTryParseOk(
+        "section.name=true", "section", null, "name", DefaultBooleanProjectConfig.Value.TRUE);
+    assertTryParseOk(
+        "section.name=TRUE", "section", null, "name", DefaultBooleanProjectConfig.Value.TRUE);
+    assertTryParseOk(
+        "section.name=forced", "section", null, "name", DefaultBooleanProjectConfig.Value.FORCED);
+    assertTryParseOk(
+        "section.name=FORCED", "section", null, "name", DefaultBooleanProjectConfig.Value.FORCED);
+
+    // assert invalid values
+    assertTryParseFail(null);
+
+    // key is missing
+    assertTryParseFail("true");
+    assertTryParseFail("TRUE");
+    assertTryParseFail("=true");
+    assertTryParseFail("=TRUE");
+
+    // value is missing
+    assertTryParseFail("receive.rejectImplicitMerges");
+    assertTryParseFail("receive.rejectImplicitMerges=");
+
+    // key and value not separated by '='
+    assertTryParseFail("receive.rejectImplicitMerges:true");
+
+    // section or name is missing
+    assertTryParseFail("foo=true");
+
+    // key has too many parts
+    assertTryParseFail("section.subsection.subsubsection.name=true");
+
+    // invalid value
+    assertTryParseFail("section.subsubsection.name=disabled");
+
+    // empty key parts
+    assertTryParseFail("section.=true");
+    assertTryParseFail(".key=true");
+    assertTryParseFail("section..key=true");
+    assertTryParseFail(".subsection.key=true");
+    assertTryParseFail("section.subsection.=true");
+    assertTryParseFail("section..=true");
+    assertTryParseFail(".subsection.=true");
+    assertTryParseFail("..key=true");
+    assertTryParseFail(".=true");
+    assertTryParseFail("..=true");
+  }
+
+  private void assertTryParseOk(
+      String s,
+      String expectedSection,
+      @Nullable String expectedSubSection,
+      String expectedName,
+      DefaultBooleanProjectConfig.Value expectedDefaultValue) {
+    Optional<DefaultBooleanProjectConfig> defaultBooleanProjectConfig =
+        DefaultBooleanProjectConfig.tryParse(s);
+    assertThat(defaultBooleanProjectConfig).isPresent();
+
+    assertThat(defaultBooleanProjectConfig.get().section()).isEqualTo(expectedSection);
+    assertThat(defaultBooleanProjectConfig.get().subSection())
+        .isEqualTo(Optional.ofNullable(expectedSubSection));
+    assertThat(defaultBooleanProjectConfig.get().name()).isEqualTo(expectedName);
+    assertThat(defaultBooleanProjectConfig.get().defaultValue()).isEqualTo(expectedDefaultValue);
+  }
+
+  private void assertTryParseFail(String s) {
+    assertThat(DefaultBooleanProjectConfig.tryParse(s)).isEmpty();
+  }
+}
diff --git a/javatests/com/google/gerrit/server/config/RepositoryConfigTest.java b/javatests/com/google/gerrit/server/config/RepositoryConfigTest.java
index 8d93f66..b3da36a 100644
--- a/javatests/com/google/gerrit/server/config/RepositoryConfigTest.java
+++ b/javatests/com/google/gerrit/server/config/RepositoryConfigTest.java
@@ -17,6 +17,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.ImmutableList;
+import com.google.gerrit.entities.BooleanProjectConfig;
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.client.SubmitType;
 import java.nio.file.Path;
@@ -96,6 +97,72 @@
   }
 
   @Test
+  public void defaultConfigForSpecificFilter() {
+    configureDefaultConfig(
+        "someProject", "receive.rejectImplicitMerges", DefaultBooleanProjectConfig.Value.FORCED);
+    assertThat(
+            repoCfg.getDefault(
+                Project.nameKey("someProject"), BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isEqualTo(DefaultBooleanProjectConfig.Value.FORCED);
+    assertThat(
+            repoCfg.getDefault(
+                Project.nameKey("someOtherProject"), BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isEqualTo(DefaultBooleanProjectConfig.Value.FALSE);
+
+    // for another key the default is false
+    assertThat(
+            repoCfg.getDefault(
+                Project.nameKey("someProject"),
+                BooleanProjectConfig.CREATE_NEW_CHANGE_FOR_ALL_NOT_IN_TARGET))
+        .isEqualTo(DefaultBooleanProjectConfig.Value.FALSE);
+  }
+
+  @Test
+  public void defaultConfigForStartWithFilter() {
+    configureDefaultConfig(
+        "somePath/somePath/*",
+        "receive.rejectImplicitMerges",
+        DefaultBooleanProjectConfig.Value.FORCED);
+    configureDefaultConfig(
+        "somePath/*", "receive.rejectImplicitMerges", DefaultBooleanProjectConfig.Value.FALSE);
+    configureDefaultConfig(
+        "*", "receive.rejectImplicitMerges", DefaultBooleanProjectConfig.Value.TRUE);
+
+    assertThat(
+            repoCfg.getDefault(
+                Project.nameKey("someProject"), BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isEqualTo(DefaultBooleanProjectConfig.Value.TRUE);
+
+    assertThat(
+            repoCfg.getDefault(
+                Project.nameKey("somePath/someProject"),
+                BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isEqualTo(DefaultBooleanProjectConfig.Value.FALSE);
+
+    assertThat(
+            repoCfg.getDefault(
+                Project.nameKey("somePath/somePath/someProject"),
+                BooleanProjectConfig.REJECT_IMPLICIT_MERGES))
+        .isEqualTo(DefaultBooleanProjectConfig.Value.FORCED);
+
+    // for another key the default is false
+    assertThat(
+            repoCfg.getDefault(
+                Project.nameKey("someProject"),
+                BooleanProjectConfig.CREATE_NEW_CHANGE_FOR_ALL_NOT_IN_TARGET))
+        .isEqualTo(DefaultBooleanProjectConfig.Value.FALSE);
+  }
+
+  private void configureDefaultConfig(
+      String projectFilter, String key, DefaultBooleanProjectConfig.Value defaultValue) {
+    cfg.setString(
+        RepositoryConfig.SECTION_NAME,
+        projectFilter,
+        RepositoryConfig.DEFAULT_CONFIG_NAME,
+        String.format("%s=%s", key, defaultValue.name()));
+  }
+
+  @Test
   public void ownerGroupsWhenNotConfigured() {
     assertThat(repoCfg.getOwnerGroups(Project.nameKey("someProject"))).isEmpty();
   }
diff --git a/package.json b/package.json
index 93123ee..633f9b3 100644
--- a/package.json
+++ b/package.json
@@ -7,24 +7,24 @@
     "@bazel/rollup": "^5.8.1",
     "@bazel/terser": "^5.8.1",
     "@bazel/typescript": "^5.8.1",
-    "@typescript-eslint/parser": "^5.62.0"
+    "@typescript-eslint/parser": "^8.32.0"
   },
   "devDependencies": {
     "@koa/cors": "^5.0.0",
     "@types/page": "^1.11.9",
-    "@typescript-eslint/eslint-plugin": "^5.62.0",
-    "@web/dev-server": "^0.1.38",
-    "@web/dev-server-esbuild": "^0.3.6",
-    "eslint": "^8.57.1",
+    "@typescript-eslint/eslint-plugin": "^8.32.0",
+    "@web/dev-server": "^0.4.6",
+    "@web/dev-server-esbuild": "^1.0.4",
+    "eslint": "^9.26.0",
     "eslint-config-google": "^0.14.0",
-    "eslint-plugin-html": "^7.1.0",
+    "eslint-plugin-html": "^8.1.2",
     "eslint-plugin-import": "^2.31.0",
-    "eslint-plugin-jsdoc": "^44.2.7",
+    "eslint-plugin-jsdoc": "^50.6.11",
     "eslint-plugin-lit": "^1.15.0",
-    "eslint-plugin-node": "^11.1.0",
-    "eslint-plugin-prettier": "^4.2.1",
+    "eslint-plugin-n": "^17.17.0",
+    "eslint-plugin-prettier": "^5.4.0",
     "eslint-plugin-regex": "^1.10.0",
-    "gts": "^3.1.1",
+    "gts": "^6.0.2",
     "lit-analyzer": "^1.2.1",
     "npm-run-all": "^4.1.5",
     "prettier": "^2.8.8",
@@ -33,6 +33,11 @@
     "ts-lit-plugin": "^1.2.1",
     "typescript": "^4.9.5"
   },
+  "resolutions": {
+    "eslint": "^9.26.0",
+    "@typescript-eslint/eslint-plugin": "^8.32.0",
+    "@typescript-eslint/parser": "^8.32.0"
+  },
   "scripts": {
     "setup": "yarn && yarn --cwd=polygerrit-ui && yarn --cwd=polygerrit-ui/app",
     "clean": "git clean -fdx && bazel clean --expunge",
@@ -52,18 +57,13 @@
     "eslint": "npm run safe_bazelisk test polygerrit-ui/app:lint_test",
     "eslintfix": "npm run safe_bazelisk run polygerrit-ui/app:lint_bin -- -- --fix $(pwd)/polygerrit-ui/app",
     "litlint": "npm run safe_bazelisk run polygerrit-ui/app:lit_analysis",
-    "lint": "eslint -c polygerrit-ui/app/.eslintrc.js --ignore-path polygerrit-ui/app/.eslintignore polygerrit-ui/app",
+    "lint": "ESLINT_USE_FLAT_CONFIG=false eslint -c polygerrit-ui/app/.eslintrc.js --ignore-path polygerrit-ui/app/.eslintignore polygerrit-ui/app",
     "gjf": "./tools/gjf.sh run"
   },
   "repository": {
     "type": "git",
     "url": "https://gerrit.googlesource.com/gerrit"
   },
-  "resolutions": {
-    "eslint": "^8.57.1",
-    "@typescript-eslint/eslint-plugin": "^5.62.0",
-    "@typescript-eslint/parser": "^5.62.0"
-  },
   "author": "",
   "license": "Apache-2.0"
 }
\ No newline at end of file
diff --git a/plugins/codemirror-editor b/plugins/codemirror-editor
index 84f9c44..f6f73e8 160000
--- a/plugins/codemirror-editor
+++ b/plugins/codemirror-editor
@@ -1 +1 @@
-Subproject commit 84f9c4452d1e4abaa969963c1a9d73d759a0c3c3
+Subproject commit f6f73e861f8175b43a5c562db2f953e2bb38a5aa
diff --git a/plugins/package.json b/plugins/package.json
index 43e5e76..fd152f7 100644
--- a/plugins/package.json
+++ b/plugins/package.json
@@ -4,31 +4,31 @@
   "browser": true,
   "dependencies": {
     "@codemirror/autocomplete": "^6.18.6",
-    "@codemirror/commands": "^6.8.0",
+    "@codemirror/commands": "^6.8.1",
     "@codemirror/lang-cpp": "^6.0.2",
     "@codemirror/lang-css": "^6.3.1",
     "@codemirror/lang-go": "^6.0.1",
     "@codemirror/lang-html": "^6.4.9",
     "@codemirror/lang-java": "^6.0.1",
-    "@codemirror/lang-javascript": "^6.2.3",
+    "@codemirror/lang-javascript": "^6.2.4",
     "@codemirror/lang-json": "^6.0.1",
     "@codemirror/lang-less": "^6.0.2",
     "@codemirror/lang-markdown": "^6.3.2",
     "@codemirror/lang-php": "^6.0.1",
-    "@codemirror/lang-python": "^6.1.7",
+    "@codemirror/lang-python": "^6.2.1",
     "@codemirror/lang-rust": "^6.0.1",
     "@codemirror/lang-sass": "^6.0.2",
     "@codemirror/lang-sql": "^6.8.0",
     "@codemirror/lang-vue": "^0.1.3",
     "@codemirror/lang-xml": "^6.1.0",
     "@codemirror/lang-yaml": "^6.1.2",
-    "@codemirror/language": "^6.10.8",
+    "@codemirror/language": "^6.11.0",
     "@codemirror/language-data": "^6.5.1",
-    "@codemirror/legacy-modes": "^6.4.3",
-    "@codemirror/lint": "^6.8.4",
-    "@codemirror/search": "^6.5.9",
+    "@codemirror/legacy-modes": "^6.5.1",
+    "@codemirror/lint": "^6.8.5",
+    "@codemirror/search": "^6.5.11",
     "@codemirror/state": "^6.5.2",
-    "@codemirror/view": "^6.36.2",
+    "@codemirror/view": "^6.36.8",
     "@lezer/highlight": "^1.2.1",
     "@gerritcodereview/typescript-api": "3.11.0",
     "@open-wc/testing": "^4.0.0",
diff --git a/plugins/webhooks b/plugins/webhooks
index 788cf1a..b00a2c2 160000
--- a/plugins/webhooks
+++ b/plugins/webhooks
@@ -1 +1 @@
-Subproject commit 788cf1a335c25a96874b99b74d7e4183b111d2f1
+Subproject commit b00a2c28eb1412312e03b541b6e2dbeefea0247a
diff --git a/plugins/yarn.lock b/plugins/yarn.lock
index d5590a3..f88ad51 100644
--- a/plugins/yarn.lock
+++ b/plugins/yarn.lock
@@ -2,7 +2,7 @@
 # yarn lockfile v1
 
 
-"@babel/code-frame@^7.12.11", "@babel/code-frame@^7.22.5":
+"@babel/code-frame@^7.12.11":
   version "7.26.2"
   resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
   integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
@@ -26,10 +26,10 @@
     "@codemirror/view" "^6.17.0"
     "@lezer/common" "^1.0.0"
 
-"@codemirror/commands@^6.8.0":
-  version "6.8.0"
-  resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.8.0.tgz#92f200b66f852939bd6ebb90d48c2d9e9c813d64"
-  integrity sha512-q8VPEFaEP4ikSlt6ZxjB3zW72+7osfAYW9i8Zu943uqbKuz6utc1+F170hyLUCUltXORjQXRyYQNfkckzA/bPQ==
+"@codemirror/commands@^6.8.1":
+  version "6.8.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.8.1.tgz#639f5559d2f33f2582a2429c58cb0c1b925c7a30"
+  integrity sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==
   dependencies:
     "@codemirror/language" "^6.0.0"
     "@codemirror/state" "^6.4.0"
@@ -37,9 +37,9 @@
     "@lezer/common" "^1.1.0"
 
 "@codemirror/lang-angular@^0.1.0":
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/@codemirror/lang-angular/-/lang-angular-0.1.3.tgz#83035e7e9e1f0e2ba466e83d778407b519089a28"
-  integrity sha512-xgeWGJQQl1LyStvndWtruUvb4SnBZDAu/gvFH/ZU+c0W25tQR8e5hq7WTwiIY2dNxnf+49mRiGI/9yxIwB6f5w==
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-angular/-/lang-angular-0.1.4.tgz#5b9e940786ba201a9a42eab6db9501fa3fe2292a"
+  integrity sha512-oap+gsltb/fzdlTQWD6BFF4bSLKcDnlxDsLdePiJpCVNKWXSTAbiiQeYI3UmES+BLAdkmIC1WjyztC1pi/bX4g==
   dependencies:
     "@codemirror/lang-html" "^6.0.0"
     "@codemirror/lang-javascript" "^6.1.2"
@@ -101,10 +101,10 @@
     "@codemirror/language" "^6.0.0"
     "@lezer/java" "^1.0.0"
 
-"@codemirror/lang-javascript@^6.0.0", "@codemirror/lang-javascript@^6.1.2", "@codemirror/lang-javascript@^6.2.3":
-  version "6.2.3"
-  resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-6.2.3.tgz#d705c359dc816afcd3bcdf120a559f83d31d4cda"
-  integrity sha512-8PR3vIWg7pSu7ur8A07pGiYHgy3hHj+mRYRCSG8q+mPIrl0F02rgpGv+DsQTHRTc30rydOsf5PZ7yjKFg2Ackw==
+"@codemirror/lang-javascript@^6.0.0", "@codemirror/lang-javascript@^6.1.2", "@codemirror/lang-javascript@^6.2.4":
+  version "6.2.4"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz#eef2227d1892aae762f3a0f212f72bec868a02c5"
+  integrity sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==
   dependencies:
     "@codemirror/autocomplete" "^6.0.0"
     "@codemirror/language" "^6.6.0"
@@ -134,9 +134,9 @@
     "@lezer/lr" "^1.0.0"
 
 "@codemirror/lang-liquid@^6.0.0":
-  version "6.2.2"
-  resolved "https://registry.yarnpkg.com/@codemirror/lang-liquid/-/lang-liquid-6.2.2.tgz#5b5a2391ac14b6af85c520b8b81ea1f344d40a62"
-  integrity sha512-7Dm841fk37+JQW6j2rI1/uGkJyESrjzyhiIkaLjbbR0U6aFFQvMrJn35WxQreRMADMhzkyVkZM4467OR7GR8nQ==
+  version "6.2.3"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-liquid/-/lang-liquid-6.2.3.tgz#cbdb38cbf2c59bc334292420401f88aa6c4b4b27"
+  integrity sha512-yeN+nMSrf/lNii3FJxVVEGQwFG0/2eDyH6gNOj+TGCa0hlNO4bhQnoO5ISnd7JOG+7zTEcI/GOoyraisFVY7jQ==
   dependencies:
     "@codemirror/autocomplete" "^6.0.0"
     "@codemirror/lang-html" "^6.0.0"
@@ -171,10 +171,10 @@
     "@lezer/common" "^1.0.0"
     "@lezer/php" "^1.0.0"
 
-"@codemirror/lang-python@^6.0.0", "@codemirror/lang-python@^6.1.7":
-  version "6.1.7"
-  resolved "https://registry.yarnpkg.com/@codemirror/lang-python/-/lang-python-6.1.7.tgz#1906234d453517d760a57c69672f0023a8649e14"
-  integrity sha512-mZnFTsL4lW5p9ch8uKNKeRU3xGGxr1QpESLilfON2E3fQzOa/OygEMkaDvERvXDJWJA9U9oN/D4w0ZuUzNO4+g==
+"@codemirror/lang-python@^6.0.0", "@codemirror/lang-python@^6.2.1":
+  version "6.2.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-python/-/lang-python-6.2.1.tgz#37c9930716110156865a95c548aa0eef5552863a"
+  integrity sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==
   dependencies:
     "@codemirror/autocomplete" "^6.3.2"
     "@codemirror/language" "^6.8.0"
@@ -288,10 +288,10 @@
     "@codemirror/language" "^6.0.0"
     "@codemirror/legacy-modes" "^6.4.0"
 
-"@codemirror/language@^6.0.0", "@codemirror/language@^6.10.8", "@codemirror/language@^6.3.0", "@codemirror/language@^6.4.0", "@codemirror/language@^6.6.0", "@codemirror/language@^6.8.0":
-  version "6.10.8"
-  resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.10.8.tgz#3e3a346a2b0a8cf63ee1cfe03349eb1965dce5f9"
-  integrity sha512-wcP8XPPhDH2vTqf181U8MbZnW+tDyPYy0UzVOa+oHORjyT+mhhom9vBd7dApJwoDz9Nb/a8kHjJIsuA/t8vNFw==
+"@codemirror/language@^6.0.0", "@codemirror/language@^6.11.0", "@codemirror/language@^6.3.0", "@codemirror/language@^6.4.0", "@codemirror/language@^6.6.0", "@codemirror/language@^6.8.0":
+  version "6.11.0"
+  resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.11.0.tgz#5ae90972601497f4575f30811519d720bf7232c9"
+  integrity sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ==
   dependencies:
     "@codemirror/state" "^6.0.0"
     "@codemirror/view" "^6.23.0"
@@ -300,26 +300,26 @@
     "@lezer/lr" "^1.0.0"
     style-mod "^4.0.0"
 
-"@codemirror/legacy-modes@^6.4.0", "@codemirror/legacy-modes@^6.4.3":
-  version "6.4.3"
-  resolved "https://registry.yarnpkg.com/@codemirror/legacy-modes/-/legacy-modes-6.4.3.tgz#5d65c86e770a2b2380e93670d18c549ef65fd225"
-  integrity sha512-s1g+q4bil8Cs4O+ueIiKIhz9MQOGcRyxJglma8BYIWc/oEJLo13S3LYSWKaqhKwXGgt1GgZ66hCploHZD9Sstw==
+"@codemirror/legacy-modes@^6.4.0", "@codemirror/legacy-modes@^6.5.1":
+  version "6.5.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/legacy-modes/-/legacy-modes-6.5.1.tgz#6bd13fac94f67a825e5420017e0d2f3c35d09342"
+  integrity sha512-DJYQQ00N1/KdESpZV7jg9hafof/iBNp9h7TYo1SLMk86TWl9uDsVdho2dzd81K+v4retmK6mdC7WpuOQDytQqw==
   dependencies:
     "@codemirror/language" "^6.0.0"
 
-"@codemirror/lint@^6.0.0", "@codemirror/lint@^6.8.4":
-  version "6.8.4"
-  resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.8.4.tgz#7d8aa5d1a6dec89ffcc23ad45ddca2e12e90982d"
-  integrity sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==
+"@codemirror/lint@^6.0.0", "@codemirror/lint@^6.8.5":
+  version "6.8.5"
+  resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.8.5.tgz#9edaa808e764e28e07665b015951934c8ec3a418"
+  integrity sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==
   dependencies:
     "@codemirror/state" "^6.0.0"
     "@codemirror/view" "^6.35.0"
     crelt "^1.0.5"
 
-"@codemirror/search@^6.5.9":
-  version "6.5.9"
-  resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.5.9.tgz#08829cf1db9d093dd4822bb22ece93da3ebffefc"
-  integrity sha512-7DdQ9aaZMMxuWB1u6IIFWWuK9NocVZwvo4nG8QjJTS6oZGvteoLSiXw3EbVZVlO08Ri2ltO89JVInMpfcJxhtg==
+"@codemirror/search@^6.5.11":
+  version "6.5.11"
+  resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.5.11.tgz#a324ffee36e032b7f67aa31c4fb9f3e6f9f3ed63"
+  integrity sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==
   dependencies:
     "@codemirror/state" "^6.0.0"
     "@codemirror/view" "^6.0.0"
@@ -332,10 +332,10 @@
   dependencies:
     "@marijn/find-cluster-break" "^1.0.0"
 
-"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.27.0", "@codemirror/view@^6.35.0", "@codemirror/view@^6.36.2":
-  version "6.36.2"
-  resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.36.2.tgz#aeb644e161440734ac5a153bf6e5b4a4355047be"
-  integrity sha512-DZ6ONbs8qdJK0fdN7AB82CgI6tYXf4HWk1wSVa0+9bhVznCuuvhQtX8bFBoy3dv8rZSQqUd8GvhVAcielcidrA==
+"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.27.0", "@codemirror/view@^6.35.0", "@codemirror/view@^6.36.8":
+  version "6.36.8"
+  resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.36.8.tgz#d72e59d2b2d99bb5f177178f63e11cef6e605b94"
+  integrity sha512-yoRo4f+FdnD01fFt4XpfpMCcCAo9QvZOtbrXExn4SqzH32YC6LgzqxfLZw/r6Ge65xyY03mK/UfUqrVw1gFiFg==
   dependencies:
     "@codemirror/state" "^6.5.0"
     style-mod "^4.1.0"
@@ -488,7 +488,7 @@
   resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
   integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
 
-"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0":
+"@jridgewell/sourcemap-codec@^1.4.14":
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a"
   integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==
@@ -507,31 +507,31 @@
   integrity sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==
 
 "@lezer/cpp@^1.0.0":
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/@lezer/cpp/-/cpp-1.1.2.tgz#1db93b09e011e8a7a08c347c9d5b7749971253bf"
-  integrity sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/@lezer/cpp/-/cpp-1.1.3.tgz#3029a542f4624fba0ed28f96511b34b8e7906352"
+  integrity sha512-ykYvuFQKGsRi6IcE+/hCSGUhb/I4WPjd3ELhEblm2wS2cOznDFzO+ubK2c+ioysOnlZ3EduV+MVQFCPzAIoY3w==
   dependencies:
     "@lezer/common" "^1.2.0"
     "@lezer/highlight" "^1.0.0"
     "@lezer/lr" "^1.0.0"
 
 "@lezer/css@^1.1.0", "@lezer/css@^1.1.7":
-  version "1.1.10"
-  resolved "https://registry.yarnpkg.com/@lezer/css/-/css-1.1.10.tgz#99cef68b26bfdefb76e269b9ee13b0de28edd8ed"
-  integrity sha512-V5/89eDapjeAkWPBpWEfQjZ1Hag3aYUUJOL8213X0dFRuXJ4BXa5NKl9USzOnaLod4AOpmVCkduir2oKwZYZtg==
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@lezer/css/-/css-1.2.0.tgz#df954b8ac44d05f955c34fc79cd914587e704113"
+  integrity sha512-8FLXsWpwKWMqQ6XjDP0DWbMP4YdeqhIcwN8IulcBinGpu30PG74zz0c6w+Yi2DeQD9/4FXfeLp+XP90NflIkGA==
   dependencies:
     "@lezer/common" "^1.2.0"
     "@lezer/highlight" "^1.0.0"
-    "@lezer/lr" "^1.0.0"
+    "@lezer/lr" "^1.3.0"
 
 "@lezer/go@^1.0.0":
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/@lezer/go/-/go-1.0.0.tgz#26cd2463f8583e630f52e714dca6d7420c5f7d7e"
-  integrity sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/@lezer/go/-/go-1.0.1.tgz#3004b54f5e4c9719edcba98653f380baf8c0d1a2"
+  integrity sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==
   dependencies:
     "@lezer/common" "^1.2.0"
     "@lezer/highlight" "^1.0.0"
-    "@lezer/lr" "^1.0.0"
+    "@lezer/lr" "^1.3.0"
 
 "@lezer/highlight@^1.0.0", "@lezer/highlight@^1.1.3", "@lezer/highlight@^1.2.0", "@lezer/highlight@^1.2.1":
   version "1.2.1"
@@ -559,9 +559,9 @@
     "@lezer/lr" "^1.0.0"
 
 "@lezer/javascript@^1.0.0":
-  version "1.4.21"
-  resolved "https://registry.yarnpkg.com/@lezer/javascript/-/javascript-1.4.21.tgz#8ebf7d1f891c70e3d00864f5a03ac42c75d19492"
-  integrity sha512-lL+1fcuxWYPURMM/oFZLEDm0XuLN128QPV+VuGtKpeaOGdcl9F2LYC3nh1S9LkPqx9M0mndZFdXCipNAZpzIkQ==
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/@lezer/javascript/-/javascript-1.5.1.tgz#2a424a6ec29f1d4ef3c34cbccc5447e373618ad8"
+  integrity sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==
   dependencies:
     "@lezer/common" "^1.2.0"
     "@lezer/highlight" "^1.1.3"
@@ -584,13 +584,12 @@
     "@lezer/common" "^1.0.0"
 
 "@lezer/markdown@^1.0.0":
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/@lezer/markdown/-/markdown-1.4.1.tgz#cab428fb05d69148174aeeda23684a6fc102c100"
-  integrity sha512-Za5okfyWoNaX6sSZ2dm94XegaFXbkQ9UjKJ8hAoZX88XDpbu6DoR63IuSl+dqj1VkVQBQGsdr0JnTcMsogQDdw==
+  version "1.4.3"
+  resolved "https://registry.yarnpkg.com/@lezer/markdown/-/markdown-1.4.3.tgz#a742ed5e782ac4913a621dfd1e6a8e409f4dd589"
+  integrity sha512-kfw+2uMrQ/wy/+ONfrH83OkdFNM0ye5Xq96cLlaCy7h5UT9FO54DU4oRoIc0CSBh5NWmWuiIJA7NGLMJbQ+Oxg==
   dependencies:
     "@lezer/common" "^1.0.0"
     "@lezer/highlight" "^1.0.0"
-    "@marijn/buildtool" "^0.1.6"
 
 "@lezer/php@^1.0.0":
   version "1.0.2"
@@ -602,9 +601,9 @@
     "@lezer/lr" "^1.1.0"
 
 "@lezer/python@^1.1.4":
-  version "1.1.15"
-  resolved "https://registry.yarnpkg.com/@lezer/python/-/python-1.1.15.tgz#14a21b3bf1997d1b578f0bb959bf2062641798a2"
-  integrity sha512-aVQ43m2zk4FZYedCqL0KHPEUsqZOrmAvRhkhHlVPnDD1HODDyyQv5BRIuod4DadkgBEZd53vQOtXTonNbEgjrQ==
+  version "1.1.18"
+  resolved "https://registry.yarnpkg.com/@lezer/python/-/python-1.1.18.tgz#fa02fbf492741c82dc2dc98a0a042bd0d4d7f1d3"
+  integrity sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg==
   dependencies:
     "@lezer/common" "^1.2.0"
     "@lezer/highlight" "^1.0.0"
@@ -665,18 +664,6 @@
   dependencies:
     "@lit-labs/ssr-dom-shim" "^1.2.0"
 
-"@marijn/buildtool@^0.1.6":
-  version "0.1.6"
-  resolved "https://registry.yarnpkg.com/@marijn/buildtool/-/buildtool-0.1.6.tgz#56eebfa82397c81b89ffa08f30eb1e960666cd33"
-  integrity sha512-rcA2wljsM24MFAwx2U5vSBrt7IdIaPh4WPRfJPS8PuCUlbuQ8Pmky4c/ec00v3YFu90rZSbkVLnPuCeb/mUEng==
-  dependencies:
-    "@types/mocha" "^9.1.1"
-    acorn "^8.10.0"
-    acorn-walk "^8.2.0"
-    rollup "^3.28.0"
-    rollup-plugin-dts "^5.3.1"
-    typescript "^5.1.6"
-
 "@marijn/find-cluster-break@^1.0.0":
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz#775374306116d51c0c500b8c4face0f9a04752d8"
@@ -1106,11 +1093,6 @@
   resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
   integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
 
-"@types/mocha@^9.1.1":
-  version "9.1.1"
-  resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4"
-  integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==
-
 "@types/node@*":
   version "22.13.4"
   resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.4.tgz#3fe454d77cd4a2d73c214008b3e331bfaaf5038a"
@@ -1384,18 +1366,6 @@
     mime-types "~2.1.34"
     negotiator "0.6.3"
 
-acorn-walk@^8.2.0:
-  version "8.3.4"
-  resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7"
-  integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==
-  dependencies:
-    acorn "^8.11.0"
-
-acorn@^8.10.0, acorn@^8.11.0:
-  version "8.14.0"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0"
-  integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
-
 agent-base@^7.1.0, agent-base@^7.1.2:
   version "7.1.3"
   resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1"
@@ -2542,13 +2512,6 @@
   resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-8.0.5.tgz#983fe337f3e176667f8e567cfcce7cb064ea214e"
   integrity sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==
 
-magic-string@^0.30.2:
-  version "0.30.17"
-  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453"
-  integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==
-  dependencies:
-    "@jridgewell/sourcemap-codec" "^1.5.0"
-
 make-dir@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e"
@@ -2916,22 +2879,6 @@
   resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
   integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
 
-rollup-plugin-dts@^5.3.1:
-  version "5.3.1"
-  resolved "https://registry.yarnpkg.com/rollup-plugin-dts/-/rollup-plugin-dts-5.3.1.tgz#c2841269a3a5cb986b7791b0328e6a178eba108f"
-  integrity sha512-gusMi+Z4gY/JaEQeXnB0RUdU82h1kF0WYzCWgVmV4p3hWXqelaKuCvcJawfeg+EKn2T1Ie+YWF2OiN1/L8bTVg==
-  dependencies:
-    magic-string "^0.30.2"
-  optionalDependencies:
-    "@babel/code-frame" "^7.22.5"
-
-rollup@^3.28.0:
-  version "3.29.5"
-  resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.5.tgz#8a2e477a758b520fb78daf04bca4c522c1da8a54"
-  integrity sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==
-  optionalDependencies:
-    fsevents "~2.3.2"
-
 rollup@^4.4.0:
   version "4.40.0"
   resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.40.0.tgz#13742a615f423ccba457554f006873d5a4de1920"
@@ -3283,11 +3230,6 @@
   resolved "https://registry.yarnpkg.com/typed-query-selector/-/typed-query-selector-2.12.0.tgz#92b65dbc0a42655fccf4aeb1a08b1dddce8af5f2"
   integrity sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==
 
-typescript@^5.1.6:
-  version "5.7.3"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e"
-  integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==
-
 typical@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
diff --git a/polygerrit-ui/app/.eslintrc.js b/polygerrit-ui/app/.eslintrc.js
index e0fe3b5..83dc482 100644
--- a/polygerrit-ui/app/.eslintrc.js
+++ b/polygerrit-ui/app/.eslintrc.js
@@ -273,6 +273,7 @@
       files: ['**/*.ts'],
       extends: [require.resolve('gts/.eslintrc.json')],
       rules: {
+        'no-constant-binary-expression': 'off',
         'regex/invalid': [
           'error', [{
             regex: '\'lit/decorators\'',
@@ -296,6 +297,9 @@
           name: '@polymer/decorators/lib/decorators',
           message: 'Use @polymer/decorators instead',
         }],
+        '@typescript-eslint/no-empty-object-type': 'off',
+        '@typescript-eslint/no-floating-promises': 'off',
+        '@typescript-eslint/no-unsafe-function-type': 'off',
         '@typescript-eslint/no-explicit-any': 'error',
         // See https://github.com/GoogleChromeLabs/shadow-selection-polyfill/issues/9
         '@typescript-eslint/ban-ts-comment': 'off',
@@ -310,19 +314,21 @@
         ],
         '@typescript-eslint/no-unused-vars': [
           'error',
-          {argsIgnorePattern: '^_'},
+          {argsIgnorePattern: '^_', caughtErrors: 'none'},
         ],
+        '@typescript-eslint/no-unused-expressions': 'off',
+        '@typescript-eslint/no-unsafe-declaration-merging': 'off',
         // https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-unsupported-features/es-builtins.md
-        'node/no-unsupported-features/es-builtins': 'off',
+        'n/no-unsupported-features/es-builtins': 'off',
         // https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-unsupported-features/node-builtins.md
-        'node/no-unsupported-features/node-builtins': 'off',
+        'n/no-unsupported-features/node-builtins': 'off',
         // Disable no-invalid-this for ts files, because it incorrectly reports
         // errors in some cases (see https://github.com/typescript-eslint/typescript-eslint/issues/491)
         // At the same tigit llme, we are using typescript in a strict mode and
         // it catches almost all errors related to invalid usage of this.
         'no-invalid-this': 'off',
 
-        'node/no-extraneous-import': 'off',
+        'n/no-extraneous-import': 'off',
 
         // Typescript already checks for undef
         'no-undef': 'off',
diff --git a/polygerrit-ui/app/.prettierrc.js b/polygerrit-ui/app/.prettierrc.js
index 8f353bf..8920451 100644
--- a/polygerrit-ui/app/.prettierrc.js
+++ b/polygerrit-ui/app/.prettierrc.js
@@ -9,7 +9,8 @@
     {
       "files": ["**/*.ts"],
       "options": {
-          ...require('gts/.prettierrc.json')
+          ...require('gts/.prettierrc.json'),
+          "trailingComma": "es5"
       }
     }
   ]
diff --git a/polygerrit-ui/app/BUILD b/polygerrit-ui/app/BUILD
index 925820c..b33da20 100644
--- a/polygerrit-ui/app/BUILD
+++ b/polygerrit-ui/app/BUILD
@@ -165,6 +165,7 @@
         "@npm//eslint-plugin-import",
         "@npm//eslint-plugin-jsdoc",
         "@npm//eslint-plugin-lit",
+        "@npm//eslint-plugin-n",
         "@npm//eslint-plugin-prettier",
         "@npm//eslint-plugin-regex",
         "@npm//gts",
diff --git a/polygerrit-ui/app/api/rest-api.ts b/polygerrit-ui/app/api/rest-api.ts
index 34fca75..962e765 100644
--- a/polygerrit-ui/app/api/rest-api.ts
+++ b/polygerrit-ui/app/api/rest-api.ts
@@ -353,7 +353,7 @@
   disable_private_changes?: boolean;
   mergeability_computation_behavior: MergeabilityComputationBehavior;
   conflicts_predicate_enabled?: boolean;
-  enable_robot_comments?: boolean;
+  allow_markdown_base64_images_in_comments?: boolean;
 }
 
 export type ChangeId = BrandType<string, '_changeId'>;
@@ -706,6 +706,8 @@
   size?: number; // in bytes
   old_mode?: number;
   new_mode?: number;
+  old_sha?: string;
+  new_sha?: string;
 }
 
 /**
@@ -1095,6 +1097,7 @@
   user: UserConfigInfo;
   default_theme?: string;
   submit_requirement_dashboard_columns?: string[];
+  dashboard_show_all_labels?: boolean;
   metadata?: MetadataInfo[];
 }
 
diff --git a/polygerrit-ui/app/api/suggestions.ts b/polygerrit-ui/app/api/suggestions.ts
index 1aa4ebe..005146d 100644
--- a/polygerrit-ui/app/api/suggestions.ts
+++ b/polygerrit-ui/app/api/suggestions.ts
@@ -67,6 +67,37 @@
    * List of supported file extensions. If undefined, all file extensions supported.
    */
   supportedFileExtensions?: string[];
+  /**
+   * Sends feedback on autocompletion suggestions.
+   * This method allows the plugin to report which suggestions were accepted or
+   * rejected by the user, which can be used for improving future suggestions.
+   */
+  sendAutocompleteFeedback?(feedbackEntries: SuggestionFeedbackEntry[]): void;
+  /**
+   * Sends feedback on 'suggest fix' (code repair) suggestions.
+   * This method allows the plugin to report which suggestions were accepted or
+   * rejected by the user, which can be used for improving future suggestions.
+   *
+   */
+  sendSuggestFixFeedback?(feedbackEntries: SuggestionFeedbackEntry[]): void;
+}
+
+/**
+ * Represents a 128-bit unique identifier for a suggestion, used for tracking feedback.
+ * The ID is split into two 64-bit BigInt components.
+ */
+export declare interface Feedback {
+  /** The least significant 64 bits of the 128-bit identifier. */
+  id1: bigint;
+  /** The most significant 64 bits of the 128-bit identifier. */
+  id2: bigint;
+}
+
+export declare interface SuggestionFeedbackEntry {
+  /** The unique identifier for the suggestion. */
+  feedbackId: Feedback;
+  /** True if the suggestion was accepted by the user, false otherwise. */
+  accepted: boolean;
 }
 
 export declare interface AutocompleteCommentResponse {
@@ -74,6 +105,7 @@
   completion?: string;
   modelVersion?: string;
   outcome?: number;
+  feedback?: Feedback;
 }
 
 export declare interface SuggestCodeResponse {
diff --git a/polygerrit-ui/app/constants/constants.ts b/polygerrit-ui/app/constants/constants.ts
index 07af328..528eb59 100644
--- a/polygerrit-ui/app/constants/constants.ts
+++ b/polygerrit-ui/app/constants/constants.ts
@@ -59,10 +59,9 @@
 export enum Tab {
   FILES = 'files',
   /**
-   * When renaming 'comments' or 'findings', UrlFormatter.java must be updated.
+   * When renaming 'comments' UrlFormatter.java must be updated.
    */
   COMMENT_THREADS = 'comments',
-  FINDINGS = 'findings',
   CHECKS = 'checks',
 }
 
diff --git a/polygerrit-ui/app/constants/messages.ts b/polygerrit-ui/app/constants/messages.ts
deleted file mode 100644
index dca1e61..0000000
--- a/polygerrit-ui/app/constants/messages.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * @license
- * Copyright 2020 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-/** Message shown when no threads in gr-thread-list for robot comments */
-export const NO_ROBOT_COMMENTS_THREADS_MSG =
-  'There are no findings for this patchset.';
diff --git a/polygerrit-ui/app/constants/reporting.ts b/polygerrit-ui/app/constants/reporting.ts
index ee9b041..0c43686 100644
--- a/polygerrit-ui/app/constants/reporting.ts
+++ b/polygerrit-ui/app/constants/reporting.ts
@@ -113,7 +113,6 @@
   COMMENT_SAVED = 'comment-saved',
   DISCARD_COMMENT = 'discard-comment',
   COMMENT_DISCARDED = 'comment-discarded',
-  ROBOT_COMMENTS_STATS = 'robot-comments-stats',
   CHECKS_TAB_RENDERED = 'checks-tab-rendered',
   CHECKS_CHIP_CLICKED = 'checks-chip-clicked',
   CHECKS_CHIP_LINK_CLICKED = 'checks-chip-link-clicked',
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
index 116c723..6b1d954 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
@@ -369,6 +369,13 @@
           id: 'labelAs-' + labelName,
         },
       });
+      labelOptions.push({
+        id: 'removeLabel-' + labelName,
+        value: {
+          name: `Remove Label ${labelName}`,
+          id: 'removeLabel-' + labelName,
+        },
+      });
     }
     return labelOptions;
   }
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.ts b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.ts
index 60bcf8a..7656671 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.ts
@@ -112,6 +112,9 @@
                     <option value="labelAs-Code-Review">
                       Label Code-Review (On Behalf Of)
                     </option>
+                    <option value="removeLabel-Code-Review">
+                      Remove Label Code-Review
+                    </option>
                     <option value="abandon">Abandon</option>
                     <option value="addPatchSet">Add Patch Set</option>
                     <option value="create">Create Reference</option>
@@ -203,6 +206,13 @@
             id: 'labelAs-Code-Review',
           },
         },
+        {
+          id: 'removeLabel-Code-Review',
+          value: {
+            name: 'Remove Label Code-Review',
+            id: 'removeLabel-Code-Review',
+          },
+        },
       ];
 
       assert.deepEqual(element.computeLabelOptions(), expectedLabelOptions);
@@ -254,6 +264,13 @@
             id: 'labelAs-Code-Review',
           },
         },
+        {
+          id: 'removeLabel-Code-Review',
+          value: {
+            name: 'Remove Label Code-Review',
+            id: 'removeLabel-Code-Review',
+          },
+        },
       ];
 
       element.section = {
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
index 1e5736b..17b9e73 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
@@ -459,6 +459,7 @@
       <div class="main table breadcrumbs">
         <gr-repo-submit-requirements
           .repo=${this.repoViewState.repo}
+          .params=${this.repoViewState}
         ></gr-repo-submit-requirements>
       </div>
     `;
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
index 27bb836..3615276 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
@@ -13,6 +13,7 @@
 import {LitElement, PropertyValues, css, html} from 'lit';
 import {customElement, property, state} from 'lit/decorators.js';
 import {BindValueChangeEvent} from '../../../types/events';
+import {ValueChangedEvent} from '../../../types/events';
 import {fireAlert, fire, fireReload} from '../../../utils/event-util';
 import {RepoDetailView} from '../../../models/views/repo';
 
@@ -45,6 +46,8 @@
   /* private but used in test */
   @state() itemAnnotation?: string;
 
+  @state() createEmptyCommit?: boolean;
+
   private readonly restApiService = getAppContext().restApiService;
 
   static override get styles() {
@@ -58,12 +61,6 @@
         input {
           width: 20em;
         }
-        /* Add css selector with #id to increase priority
-          (otherwise ".gr-form-styles section" rule wins) */
-        .hideItem,
-        #itemAnnotationSection.hideItem {
-          display: none;
-        }
       `,
     ];
   }
@@ -81,7 +78,30 @@
               <input placeholder="${this.detailType} Name" />
             </iron-input>
           </section>
-          <section id="itemRevisionSection">
+          <section
+            id="createEmptyCommitSection"
+            ?hidden=${this.itemDetail === RepoDetailView.TAGS}
+          >
+            <div>
+              <span class="title">Point to</span>
+            </div>
+            <div>
+              <span class="value">
+                <gr-select
+                  id="initialCommit"
+                  .bindValue=${this.createEmptyCommit}
+                  @bind-value-changed=${this
+                    .handleCreateEmptyCommitBindValueChanged}
+                >
+                  <select>
+                    <option value="false">Existing Revision</option>
+                    <option value="true">Initial empty commit</option>
+                  </select>
+                </gr-select>
+              </span>
+            </div>
+          </section>
+          <section id="itemRevisionSection" ?hidden=${!!this.createEmptyCommit}>
             <span class="title">Initial Revision</span>
             <iron-input
               .bindValue=${this.itemRevision}
@@ -92,9 +112,7 @@
           </section>
           <section
             id="itemAnnotationSection"
-            class=${this.itemDetail === RepoDetailView.BRANCHES
-              ? 'hideItem'
-              : ''}
+            ?hidden=${this.itemDetail === RepoDetailView.BRANCHES}
           >
             <span class="title">Annotation</span>
             <iron-input
@@ -126,10 +144,14 @@
     if (!this.itemName) {
       throw new Error('itemName name is not set');
     }
-    const USE_HEAD = this.itemRevision ? this.itemRevision : 'HEAD';
+    const useHead = this.itemRevision ? this.itemRevision : 'HEAD';
+    const createEmptyCommit = !!this.createEmptyCommit;
     if (this.itemDetail === RepoDetailView.BRANCHES) {
+      const createBranchInput = createEmptyCommit
+        ? {create_empty_commit: true}
+        : {revision: useHead};
       return this.restApiService
-        .createRepoBranch(this.repoName, this.itemName, {revision: USE_HEAD})
+        .createRepoBranch(this.repoName, this.itemName, createBranchInput)
         .then(itemRegistered => {
           if (itemRegistered.status === 201) {
             fireAlert(this, 'Branch created successfully. Reloading...');
@@ -139,7 +161,7 @@
     } else if (this.itemDetail === RepoDetailView.TAGS) {
       return this.restApiService
         .createRepoTag(this.repoName, this.itemName, {
-          revision: USE_HEAD,
+          revision: useHead,
           message: this.itemAnnotation || undefined,
         })
         .then(itemRegistered => {
@@ -163,4 +185,10 @@
   private handleItemAnnotationBindValueChanged(e: BindValueChangeEvent) {
     this.itemAnnotation = e.detail.value;
   }
+
+  private handleCreateEmptyCommitBindValueChanged(
+    e: ValueChangedEvent<string>
+  ) {
+    this.createEmptyCommit = e.detail.value === 'true';
+  }
 }
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.ts b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.ts
index 9e455d1..96c3682 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.ts
@@ -40,6 +40,21 @@
                 <input placeholder=" Name" />
               </iron-input>
             </section>
+            <section id="createEmptyCommitSection">
+              <div>
+                <span class="title">Point to</span>
+              </div>
+              <div>
+                <span class="value">
+                  <gr-select id="initialCommit">
+                    <select>
+                      <option value="false">Existing Revision</option>
+                      <option value="true">Initial empty commit</option>
+                    </select>
+                  </gr-select>
+                </span>
+              </div>
+            </section>
             <section id="itemRevisionSection">
               <span class="title"> Initial Revision </span>
               <iron-input>
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
index 077ac94..7ddda89 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
@@ -145,6 +145,36 @@
               <input id="repoNameInput" autocomplete="on" />
             </iron-input>
           </section>
+          <section>
+            <div class="title-flex">
+              <span class="title">
+                <gr-tooltip-content
+                  has-tooltip
+                  title="Only serve as a parent repository for other repositories
+to inheright access rights and configs.
+If 'true', then you cannot push code to this repo.
+It will only have a 'refs/meta/config' branch."
+                >
+                  Parent Repo Only <gr-icon icon="info"></gr-icon>
+                </gr-tooltip-content>
+              </span>
+            </div>
+            <div class="value-flex">
+              <span class="value">
+                <gr-select
+                  id="parentRepo"
+                  .bindValue=${this.repoConfig.permissions_only}
+                  @bind-value-changed=${this
+                    .handlePermissionsOnlyBindValueChanged}
+                >
+                  <select>
+                    <option value="false">False</option>
+                    <option value="true">True</option>
+                  </select>
+                </gr-select>
+              </span>
+            </div>
+          </section>
           <section ?hidden=${!!this.repoConfig.permissions_only}>
             <div class="title-flex">
               <span class="title">Default Branch</span>
@@ -232,36 +262,6 @@
               </span>
             </div>
           </section>
-          <section>
-            <div class="title-flex">
-              <span class="title">
-                <gr-tooltip-content
-                  has-tooltip
-                  title="Only serve as a parent repository for other repositories
-to inheright access rights and configs.
-If 'true', then you cannot push code to this repo.
-It will only have a 'refs/meta/config' branch."
-                >
-                  Parent Repo Only <gr-icon icon="info"></gr-icon>
-                </gr-tooltip-content>
-              </span>
-            </div>
-            <div class="value-flex">
-              <span class="value">
-                <gr-select
-                  id="parentRepo"
-                  .bindValue=${this.repoConfig.permissions_only}
-                  @bind-value-changed=${this
-                    .handlePermissionsOnlyBindValueChanged}
-                >
-                  <select>
-                    <option value="false">False</option>
-                    <option value="true">True</option>
-                  </select>
-                </gr-select>
-              </span>
-            </div>
-          </section>
         </div>
       </div>
     `;
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.ts b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.ts
index 289cd03..49787ce 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.ts
@@ -41,6 +41,32 @@
             </section>
             <section>
               <div class="title-flex">
+                <span class="title">
+                  <gr-tooltip-content
+                    has-tooltip=""
+                    title="Only serve as a parent repository for other repositories
+to inheright access rights and configs.
+If 'true', then you cannot push code to this repo.
+It will only have a 'refs/meta/config' branch."
+                  >
+                    Parent Repo Only
+                    <gr-icon icon="info"> </gr-icon>
+                  </gr-tooltip-content>
+                </span>
+              </div>
+              <div class="value-flex">
+                <span class="value">
+                  <gr-select id="parentRepo">
+                    <select>
+                      <option value="false">False</option>
+                      <option value="true">True</option>
+                    </select>
+                  </gr-select>
+                </span>
+              </div>
+            </section>
+            <section>
+              <div class="title-flex">
                 <span class="title"> Default Branch </span>
               </div>
               <span class="value">
@@ -102,32 +128,6 @@
                 </span>
               </div>
             </section>
-            <section>
-              <div class="title-flex">
-                <span class="title">
-                  <gr-tooltip-content
-                    has-tooltip=""
-                    title="Only serve as a parent repository for other repositories
-to inheright access rights and configs.
-If 'true', then you cannot push code to this repo.
-It will only have a 'refs/meta/config' branch."
-                  >
-                    Parent Repo Only
-                    <gr-icon icon="info"> </gr-icon>
-                  </gr-tooltip-content>
-                </span>
-              </div>
-              <div class="value-flex">
-                <span class="value">
-                  <gr-select id="parentRepo">
-                    <select>
-                      <option value="false">False</option>
-                      <option value="true">True</option>
-                    </select>
-                  </gr-select>
-                </span>
-              </div>
-            </section>
           </div>
         </div>
       `
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
index 17e24b5..66a461e 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
@@ -157,6 +157,7 @@
         .weblinks.show,
         .referenceContainer {
           display: block;
+          align-content: center;
         }
         .rightsText {
           margin-right: var(--spacing-s);
@@ -165,11 +166,15 @@
         .editing gr-button,
         .admin #editBtn {
           display: inline-block;
-          margin: var(--spacing-l) 0;
+          margin: var(--spacing-l);
         }
         .editing #editInheritFromInput {
           display: inline-block;
         }
+
+        .topLevelButtons {
+          display: flex;
+        }
       `,
     ];
   }
@@ -210,11 +215,40 @@
               }}
             ></gr-autocomplete>
           </h3>
-          <div class="weblinks ${this.weblinks?.length ? 'show' : ''}">
-            History:
-            ${this.weblinks?.map(
-              info => html`<gr-weblink .info=${info}></gr-weblink>`
-            )}
+          <div class="topLevelButtons">
+            <div class="weblinks ${this.weblinks?.length ? 'show' : ''}">
+              History:
+              ${this.weblinks?.map(
+                info => html`<gr-weblink .info=${info}></gr-weblink>`
+              )}
+            </div>
+            <div>
+              <gr-button
+                id="editBtn"
+                @click=${() => {
+                  this.handleEdit();
+                }}
+                >${this.editing ? 'Cancel' : 'Edit'}</gr-button
+              >
+              <gr-button
+                id="saveBtn"
+                class=${this.ownerOf && this.ownerOf.length === 0
+                  ? 'invisible'
+                  : ''}
+                primary
+                ?disabled=${!this.modified || this.disableSaveWithoutReview}
+                @click=${this.handleSave}
+                >Save</gr-button
+              >
+              <gr-button
+                id="saveReviewBtn"
+                class=${!this.canUpload ? 'invisible' : ''}
+                primary
+                ?disabled=${!this.modified}
+                @click=${this.handleSaveForReview}
+                >Save For Review</gr-button
+              >
+            </div>
           </div>
           ${this.sections?.map((section, index) =>
             this.renderPermissionSections(section, index)
@@ -226,33 +260,6 @@
               >Add Reference</gr-button
             >
           </div>
-          <div>
-            <gr-button
-              id="editBtn"
-              @click=${() => {
-                this.handleEdit();
-              }}
-              >${this.editing ? 'Cancel' : 'Edit'}</gr-button
-            >
-            <gr-button
-              id="saveBtn"
-              class=${this.ownerOf && this.ownerOf.length === 0
-                ? 'invisible'
-                : ''}
-              primary
-              ?disabled=${!this.modified || this.disableSaveWithoutReview}
-              @click=${this.handleSave}
-              >Save</gr-button
-            >
-            <gr-button
-              id="saveReviewBtn"
-              class=${!this.canUpload ? 'invisible' : ''}
-              primary
-              ?disabled=${!this.modified}
-              @click=${this.handleSaveForReview}
-              >Save For Review</gr-button
-            >
-          </div>
         </div>
       </div>
     `;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.ts
index d5eb17a..6437e9f 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.ts
@@ -137,7 +137,40 @@
               <a href="" id="inheritFromName" rel="noopener"> </a>
               <gr-autocomplete id="editInheritFromInput"> </gr-autocomplete>
             </h3>
-            <div class="weblinks">History:</div>
+            <div class="topLevelButtons">
+              <div class="weblinks">History:</div>
+              <div>
+                <gr-button
+                  aria-disabled="false"
+                  id="editBtn"
+                  role="button"
+                  tabindex="0"
+                >
+                  Edit
+                </gr-button>
+                <gr-button
+                  aria-disabled="true"
+                  disabled=""
+                  class="invisible"
+                  id="saveBtn"
+                  primary=""
+                  role="button"
+                  tabindex="-1"
+                >
+                  Save
+                </gr-button>
+                <gr-button
+                  aria-disabled="false"
+                  class="invisible"
+                  id="saveReviewBtn"
+                  primary=""
+                  role="button"
+                  tabindex="0"
+                >
+                  Save For Review
+                </gr-button>
+              </div>
+            </div>
             <div class="referenceContainer">
               <gr-button
                 aria-disabled="false"
@@ -148,37 +181,6 @@
                 Add Reference
               </gr-button>
             </div>
-            <div>
-              <gr-button
-                aria-disabled="false"
-                id="editBtn"
-                role="button"
-                tabindex="0"
-              >
-                Edit
-              </gr-button>
-              <gr-button
-                aria-disabled="true"
-                disabled=""
-                class="invisible"
-                id="saveBtn"
-                primary=""
-                role="button"
-                tabindex="-1"
-              >
-                Save
-              </gr-button>
-              <gr-button
-                aria-disabled="false"
-                class="invisible"
-                id="saveReviewBtn"
-                primary=""
-                role="button"
-                tabindex="0"
-              >
-                Save For Review
-              </gr-button>
-            </div>
           </div>
         </div>
       `
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.ts
index 8a0bac3..e36cb32 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.ts
@@ -2193,7 +2193,7 @@
       });
 
       test('test for tag message in the list', async () => {
-        assert.equal((element.items as TagInfo[])![2].message, 'Annotated tag');
+        assert.equal((element.items as TagInfo[])[2].message, 'Annotated tag');
       });
 
       test('test for tagger in the tag list', async () => {
@@ -2203,7 +2203,7 @@
           date: '2017-09-19 14:54:00.000000000' as Timestamp,
         };
 
-        assert.deepEqual((element.items as TagInfo[])![2].tagger, tagger);
+        assert.deepEqual((element.items as TagInfo[])[2].tagger, tagger);
       });
 
       test('test for web links in the tags list', async () => {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-submit-requirements/gr-repo-submit-requirements.ts b/polygerrit-ui/app/elements/admin/gr-repo-submit-requirements/gr-repo-submit-requirements.ts
index 6de8705..b978ddb 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-submit-requirements/gr-repo-submit-requirements.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-submit-requirements/gr-repo-submit-requirements.ts
@@ -3,98 +3,264 @@
  * Copyright 2025 Google LLC
  * SPDX-License-Identifier: Apache-2.0
  */
-import {RepoName, SubmitRequirementInfo} from '../../../types/common';
+import {
+  RepoName,
+  SubmitRequirementInfo,
+  SubmitRequirementInput,
+} from '../../../types/common';
 import {firePageError} from '../../../utils/event-util';
 import {getAppContext} from '../../../services/app-context';
 import {ErrorCallback} from '../../../api/rest';
 import {sharedStyles} from '../../../styles/shared-styles';
 import {tableStyles} from '../../../styles/gr-table-styles';
-import {LitElement, css, html, PropertyValues} from 'lit';
-import {customElement, property, state} from 'lit/decorators.js';
+import {LitElement, css, html, PropertyValues, nothing} from 'lit';
+import {customElement, property, state, query} from 'lit/decorators.js';
 import {when} from 'lit/directives/when.js';
+import {grFormStyles} from '../../../styles/gr-form-styles';
+import {assertIsDefined} from '../../../utils/common-util';
+import {modalStyles} from '../../../styles/gr-modal-styles';
+import '../../shared/gr-list-view/gr-list-view';
+import {
+  createRepoUrl,
+  RepoDetailView,
+  RepoViewState,
+} from '../../../models/views/repo';
+import '@polymer/iron-input/iron-input';
 
 @customElement('gr-repo-submit-requirements')
 export class GrRepoSubmitRequirements extends LitElement {
   @property({type: String})
   repo?: RepoName;
 
+  @property({type: Object})
+  params?: RepoViewState;
+
+  @query('#createDialog')
+  private readonly createDialog?: HTMLDialogElement;
+
+  @query('#deleteDialog')
+  private readonly deleteDialog?: HTMLDialogElement;
+
   @state()
   loading = true;
 
   @state()
   submitRequirements?: SubmitRequirementInfo[];
 
+  @state()
+  showCreateDialog = false;
+
+  @state() isProjectOwner = false;
+
+  @state()
+  newRequirement: SubmitRequirementInput = this.getEmptyRequirement();
+
+  @state() offset = 0;
+
+  @state() filter = '';
+
+  @state() itemsPerPage = 25;
+
+  @state() showDeleteDialog = false;
+
+  @state() requirementToDelete?: SubmitRequirementInfo;
+
+  @state()
+  requirementToEdit?: SubmitRequirementInfo;
+
+  @state()
+  isEditing = false;
+
   private readonly restApiService = getAppContext().restApiService;
 
   static override get styles() {
     return [
       sharedStyles,
       tableStyles,
+      grFormStyles,
+      modalStyles,
       css`
         :host {
           display: block;
           margin-bottom: var(--spacing-xxl);
         }
+        .actions {
+          display: flex;
+          justify-content: flex-end;
+          margin-bottom: var(--spacing-m);
+          padding: var(--spacing-l);
+        }
+        .createButton {
+          margin-left: var(--spacing-m);
+        }
+        .deleteBtn {
+          --gr-button-padding: var(--spacing-s) var(--spacing-m);
+        }
+        div.title-flex,
+        div.value-flex {
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+        }
+        input {
+          width: 20em;
+          box-sizing: border-box;
+        }
+        div.gr-form-styles section {
+          margin: var(--spacing-m) 0;
+        }
+        div.gr-form-styles span.title {
+          width: 13em;
+        }
+        section .title gr-icon {
+          vertical-align: top;
+        }
+        textarea {
+          width: 20em;
+          min-height: 100px;
+          resize: vertical;
+          box-sizing: border-box;
+        }
+        gr-dialog {
+          width: 36em;
+        }
       `,
     ];
   }
 
+  constructor() {
+    super();
+    if (this.repo) {
+      this.checkProjectOwner();
+    }
+  }
+
+  private async checkProjectOwner() {
+    if (!this.repo) return;
+    try {
+      const access = await this.restApiService.getRepoAccessRights(this.repo);
+      this.isProjectOwner = !!access?.is_owner;
+    } catch (e) {
+      console.error('Failed to check project owner status:', e);
+      this.isProjectOwner = false;
+    }
+  }
+
   override render() {
-    return html` <table id="list" class="genericList">
-      <tbody>
-        <tr class="headerRow">
-          <th class="topHeader">Name</th>
-          <th class="topHeader">Description</th>
-          <th class="topHeader">Applicability Expression</th>
-          <th class="topHeader">Submittability Expression</th>
-          <th class="topHeader">Override Expression</th>
-          <th
-            class="topHeader"
-            title="Whether override is allowed in child projects"
-          >
-            Allow Override
-          </th>
-        </tr>
-      </tbody>
-      <tbody id="submit-requirements">
-        ${when(
-          this.loading,
-          () => html`<tr id="loadingContainer">
-            <td>Loading...</td>
-          </tr>`,
-          () =>
-            html` ${(this.submitRequirements ?? []).map(
-              item => html`
-                <tr class="table">
-                  <td class="name">${item.name}</td>
-                  <td class="desc">${item.description}</td>
-                  <td class="applicability">
-                    ${item.applicability_expression}
-                  </td>
-                  <td class="submittability">
-                    ${item.submittability_expression}
-                  </td>
-                  <td class="override">${item.override_expression}</td>
-                  <td class="allowOverride">
-                    ${this.renderCheckmark(
-                      item.allow_override_in_child_projects
-                    )}
-                  </td>
-                </tr>
-              `
-            )}`
-        )}
-      </tbody>
-    </table>`;
+    return html`
+      <gr-list-view
+        .createNew=${this.isProjectOwner}
+        .filter=${this.filter}
+        .itemsPerPage=${this.itemsPerPage}
+        .items=${this.submitRequirements}
+        .loading=${this.loading}
+        .offset=${this.offset}
+        .path=${createRepoUrl({
+          repo: this.repo,
+          detail: RepoDetailView.SUBMIT_REQUIREMENTS,
+        })}
+        @create-clicked=${() => this.handleCreateClick()}
+      >
+        <table id="list" class="genericList">
+          <tbody>
+            <tr class="headerRow">
+              <th class="topHeader">Name</th>
+              <th class="topHeader">Description</th>
+              <th class="topHeader">Applicability Expression</th>
+              <th class="topHeader">Submittability Expression</th>
+              <th class="topHeader">Override Expression</th>
+              <th
+                class="topHeader"
+                title="Whether override is allowed in child projects"
+              >
+                Allow Override
+              </th>
+              ${when(
+                this.isProjectOwner,
+                () => html`<th class="topHeader"></th>`
+              )}
+            </tr>
+          </tbody>
+          <tbody id="submit-requirements">
+            ${when(
+              this.loading,
+              () => html`<tr id="loadingContainer">
+                <td>Loading...</td>
+              </tr>`,
+              () =>
+                html` ${(this.submitRequirements ?? []).map(
+                  item => html`
+                    <tr class="table">
+                      <td class="name">${item.name}</td>
+                      <td class="desc">${item.description}</td>
+                      <td class="applicability">
+                        ${item.applicability_expression}
+                      </td>
+                      <td class="submittability">
+                        ${item.submittability_expression}
+                      </td>
+                      <td class="override">${item.override_expression}</td>
+                      <td class="allowOverride">
+                        ${this.renderCheckmark(
+                          item.allow_override_in_child_projects
+                        )}
+                      </td>
+                      ${when(
+                        this.isProjectOwner,
+                        () => html`
+                          <td class="actions">
+                            <gr-button
+                              class="editBtn"
+                              link
+                              @click=${() => this.handleEditClick(item)}
+                            >
+                              Edit
+                            </gr-button>
+                            <gr-button
+                              class="deleteBtn"
+                              link
+                              @click=${() => this.handleDeleteClick(item)}
+                            >
+                              Delete
+                            </gr-button>
+                          </td>
+                        `
+                      )}
+                    </tr>
+                  `
+                )}`
+            )}
+          </tbody>
+        </table>
+      </gr-list-view>
+
+      ${this.renderCreateDialog()} ${this.renderDeleteDialog()}
+    `;
   }
 
   override updated(changedProperties: PropertyValues) {
     if (changedProperties.has('repo')) {
-      this.repoChanged();
+      this.getSubmitRequirements();
+      this.checkProjectOwner();
     }
   }
 
-  private repoChanged() {
+  override willUpdate(changedProperties: PropertyValues) {
+    if (changedProperties.has('params')) {
+      this._paramsChanged();
+    }
+  }
+
+  async _paramsChanged() {
+    const params = this.params;
+    this.loading = true;
+    this.filter = params?.filter ?? '';
+    this.offset = Number(params?.offset ?? 0);
+
+    await this.getSubmitRequirements(this.filter, this.offset);
+  }
+
+  private getSubmitRequirements(filter?: string, offset?: number) {
     const repo = this.repo;
     this.loading = true;
     if (!repo) {
@@ -112,7 +278,13 @@
           return;
         }
 
-        this.submitRequirements = res;
+        this.submitRequirements = res
+          .filter(item =>
+            filter === undefined
+              ? true
+              : item.name.toLowerCase().includes(filter.toLowerCase())
+          )
+          .slice(offset ?? 0, (offset ?? 0) + this.itemsPerPage);
         this.loading = false;
       });
   }
@@ -120,6 +292,298 @@
   private renderCheckmark(check?: boolean) {
     return check ? '✓' : '';
   }
+
+  private handleCreateClick() {
+    this.isEditing = false;
+    this.newRequirement = this.getEmptyRequirement();
+    assertIsDefined(this.createDialog, 'createDialog');
+    this.createDialog.showModal();
+  }
+
+  private handleEditClick(requirement: SubmitRequirementInfo) {
+    this.isEditing = true;
+    this.requirementToEdit = requirement;
+    this.newRequirement = {
+      name: requirement.name,
+      description: requirement.description || '',
+      applicability_expression: requirement.applicability_expression || '',
+      submittability_expression: requirement.submittability_expression || '',
+      override_expression: requirement.override_expression || '',
+      allow_override_in_child_projects:
+        requirement.allow_override_in_child_projects || false,
+    };
+    assertIsDefined(this.createDialog, 'createDialog');
+    this.createDialog.showModal();
+  }
+
+  private handleCreateCancel() {
+    assertIsDefined(this.createDialog, 'createDialog');
+    this.createDialog.close();
+    this.newRequirement = this.getEmptyRequirement();
+    this.requirementToEdit = undefined;
+    this.isEditing = false;
+  }
+
+  private handleCreateConfirm() {
+    if (!this.repo) return;
+    if (
+      !this.newRequirement.name ||
+      !this.newRequirement.submittability_expression
+    ) {
+      return;
+    }
+
+    const errFn: ErrorCallback = response => {
+      firePageError(response);
+    };
+
+    const promise =
+      this.isEditing && this.requirementToEdit
+        ? this.restApiService.updateSubmitRequirement(
+            this.repo,
+            this.requirementToEdit.name,
+            this.newRequirement,
+            errFn
+          )
+        : this.restApiService.createSubmitRequirement(
+            this.repo,
+            this.newRequirement,
+            errFn
+          );
+
+    promise.then(() => {
+      this.createDialog?.close();
+      this.newRequirement = this.getEmptyRequirement();
+      this.requirementToEdit = undefined;
+      this.isEditing = false;
+      this.getSubmitRequirements(this.filter, this.offset);
+    });
+  }
+
+  private getEmptyRequirement(): SubmitRequirementInput {
+    return {
+      name: '',
+      description: '',
+      applicability_expression: '',
+      submittability_expression: '',
+      override_expression: '',
+      allow_override_in_child_projects: false,
+    };
+  }
+
+  private renderCreateDialog() {
+    if (!this.isProjectOwner) return nothing;
+
+    return html`
+      <dialog id="createDialog" tabindex="-1">
+        <gr-dialog
+          confirm-label=${this.isEditing ? 'Save' : 'Create'}
+          cancel-label="Cancel"
+          ?disabled=${!this.newRequirement.name ||
+          !this.newRequirement.submittability_expression}
+          @confirm=${this.handleCreateConfirm}
+          @cancel=${this.handleCreateCancel}
+        >
+          <div class="header" slot="header">
+            ${this.isEditing ? 'Edit' : 'Create'} Submit Requirement
+          </div>
+          <div class="main" slot="main">
+            <div class="gr-form-styles">
+              <div id="form">
+                <section>
+                  <div class="title-flex">
+                    <span class="title">Name</span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <iron-input
+                        .bindValue=${this.newRequirement.name}
+                        @bind-value-changed=${(e: Event) => {
+                          this.newRequirement = {
+                            ...this.newRequirement,
+                            name: (e as CustomEvent).detail.value,
+                          };
+                        }}
+                      >
+                        <input
+                          id="name"
+                          type="text"
+                          required
+                          ?disabled=${this.isEditing}
+                        />
+                      </iron-input>
+                    </span>
+                  </div>
+                </section>
+                <section>
+                  <div class="title-flex">
+                    <span class="title">Description</span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <textarea
+                        id="description"
+                        .value=${this.newRequirement.description}
+                        placeholder="Optional"
+                      ></textarea>
+                    </span>
+                  </div>
+                </section>
+                <section>
+                  <div class="title-flex">
+                    <span class="title">Applicability Expression</span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <iron-input
+                        .bindValue=${this.newRequirement
+                          .applicability_expression}
+                        @bind-value-changed=${(e: Event) => {
+                          this.newRequirement = {
+                            ...this.newRequirement,
+                            applicability_expression: (e as CustomEvent).detail
+                              .value,
+                          };
+                        }}
+                      >
+                        <input
+                          id="applicability"
+                          type="text"
+                          placeholder="Optional"
+                        />
+                      </iron-input>
+                    </span>
+                  </div>
+                </section>
+                <section>
+                  <div class="title-flex">
+                    <span class="title">Submittability Expression</span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <iron-input
+                        .bindValue=${this.newRequirement
+                          .submittability_expression}
+                        @bind-value-changed=${(e: Event) => {
+                          this.newRequirement = {
+                            ...this.newRequirement,
+                            submittability_expression: (e as CustomEvent).detail
+                              .value,
+                          };
+                        }}
+                      >
+                        <input id="submittability" type="text" required />
+                      </iron-input>
+                    </span>
+                  </div>
+                </section>
+                <section>
+                  <div class="title-flex">
+                    <span class="title">Override Expression</span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <iron-input
+                        .bindValue=${this.newRequirement.override_expression}
+                        @bind-value-changed=${(e: Event) => {
+                          this.newRequirement = {
+                            ...this.newRequirement,
+                            override_expression: (e as CustomEvent).detail
+                              .value,
+                          };
+                        }}
+                      >
+                        <input
+                          id="override"
+                          type="text"
+                          placeholder="Optional"
+                        />
+                      </iron-input>
+                    </span>
+                  </div>
+                </section>
+                <section>
+                  <div class="title-flex">
+                    <span class="title">Allow Override in Child Projects</span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <gr-select
+                        id="allowOverride"
+                        .bindValue=${this.newRequirement
+                          .allow_override_in_child_projects}
+                        @bind-value-changed=${(e: Event) => {
+                          this.newRequirement = {
+                            ...this.newRequirement,
+                            allow_override_in_child_projects:
+                              (e as CustomEvent).detail.value === 'true',
+                          };
+                        }}
+                      >
+                        <select>
+                          <option value="true">True</option>
+                          <option value="false">False</option>
+                        </select>
+                      </gr-select>
+                    </span>
+                  </div>
+                </section>
+              </div>
+            </div>
+          </div>
+        </gr-dialog>
+      </dialog>
+    `;
+  }
+
+  private renderDeleteDialog() {
+    if (!this.isProjectOwner) return nothing;
+
+    return html`
+      <dialog id="deleteDialog" tabindex="-1">
+        <gr-dialog
+          confirm-label="Delete"
+          cancel-label="Cancel"
+          @confirm=${this.handleDeleteConfirm}
+          @cancel=${this.handleDeleteCancel}
+        >
+          <div class="header" slot="header">Delete Submit Requirement</div>
+          <div class="main" slot="main">
+            Are you sure you want to delete the submit requirement
+            "${this.requirementToDelete?.name}"?
+          </div>
+        </gr-dialog>
+      </dialog>
+    `;
+  }
+
+  private handleDeleteClick(requirement: SubmitRequirementInfo) {
+    this.requirementToDelete = requirement;
+    assertIsDefined(this.deleteDialog, 'deleteDialog');
+    this.deleteDialog.showModal();
+  }
+
+  private handleDeleteCancel() {
+    assertIsDefined(this.deleteDialog, 'deleteDialog');
+    this.deleteDialog.close();
+    this.requirementToDelete = undefined;
+  }
+
+  private handleDeleteConfirm() {
+    if (!this.repo || !this.requirementToDelete) return;
+
+    const errFn: ErrorCallback = response => {
+      firePageError(response);
+    };
+
+    this.restApiService
+      .deleteSubmitRequirement(this.repo, this.requirementToDelete.name, errFn)
+      .then(() => {
+        this.deleteDialog?.close();
+        this.requirementToDelete = undefined;
+        this.getSubmitRequirements(this.filter, this.offset);
+      });
+  }
 }
 
 declare global {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-submit-requirements/gr-repo-submit-requirements_test.ts b/polygerrit-ui/app/elements/admin/gr-repo-submit-requirements/gr-repo-submit-requirements_test.ts
index f438a68..8cefd53 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-submit-requirements/gr-repo-submit-requirements_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-submit-requirements/gr-repo-submit-requirements_test.ts
@@ -6,9 +6,14 @@
 import '../../../test/common-test-setup';
 import './gr-repo-submit-requirements';
 import {GrRepoSubmitRequirements} from './gr-repo-submit-requirements';
-import {stubRestApi, waitEventLoop} from '../../../test/test-utils';
+import {
+  queryAndAssert,
+  stubRestApi,
+  waitEventLoop,
+} from '../../../test/test-utils';
 import {RepoName, SubmitRequirementInfo} from '../../../types/common';
 import {fixture, html, assert} from '@open-wc/testing';
+import {GrButton} from '../../shared/gr-button/gr-button';
 
 suite('gr-repo-submit-requirements tests', () => {
   let element: GrRepoSubmitRequirements;
@@ -38,36 +43,7 @@
       element.repo = 'test2' as RepoName;
       assert.shadowDom.equal(
         element,
-        /* HTML */ `<table class="genericList" id="list">
-          <tbody>
-            <tr class="headerRow">
-              <th class="topHeader">Name</th>
-              <th class="topHeader">Description</th>
-              <th class="topHeader">Applicability Expression</th>
-              <th class="topHeader">Submittability Expression</th>
-              <th class="topHeader">Override Expression</th>
-              <th
-                class="topHeader"
-                title="Whether override is allowed in child projects"
-              >
-                Allow Override
-              </th>
-            </tr>
-          </tbody>
-          <tbody id="submit-requirements">
-            <tr id="loadingContainer">
-              <td>Loading...</td>
-            </tr>
-          </tbody>
-        </table>`
-      );
-    });
-
-    test('render', async () => {
-      await waitEventLoop();
-      assert.shadowDom.equal(
-        element,
-        /* HTML */ `
+        /* HTML */ `<gr-list-view>
           <table class="genericList" id="list">
             <tbody>
               <tr class="headerRow">
@@ -85,22 +61,309 @@
               </tr>
             </tbody>
             <tbody id="submit-requirements">
-              <tr class="table">
-                <td class="name">Verified</td>
-                <td class="desc">
-                  CI result status for build and tests is passing
-                </td>
-                <td class="applicability"></td>
-                <td class="submittability">
-                  label:Verified=MAX AND -label:Verified=MIN
-                </td>
-                <td class="override"></td>
-                <td class="allowOverride"></td>
+              <tr id="loadingContainer">
+                <td>Loading...</td>
               </tr>
             </tbody>
           </table>
+        </gr-list-view>`
+      );
+    });
+
+    test('render', async () => {
+      await waitEventLoop();
+      assert.shadowDom.equal(
+        element,
+        /* HTML */ `
+          <gr-list-view>
+            <table class="genericList" id="list">
+              <tbody>
+                <tr class="headerRow">
+                  <th class="topHeader">Name</th>
+                  <th class="topHeader">Description</th>
+                  <th class="topHeader">Applicability Expression</th>
+                  <th class="topHeader">Submittability Expression</th>
+                  <th class="topHeader">Override Expression</th>
+                  <th
+                    class="topHeader"
+                    title="Whether override is allowed in child projects"
+                  >
+                    Allow Override
+                  </th>
+                </tr>
+              </tbody>
+              <tbody id="submit-requirements">
+                <tr class="table">
+                  <td class="name">Verified</td>
+                  <td class="desc">
+                    CI result status for build and tests is passing
+                  </td>
+                  <td class="applicability"></td>
+                  <td class="submittability">
+                    label:Verified=MAX AND -label:Verified=MIN
+                  </td>
+                  <td class="override"></td>
+                  <td class="allowOverride"></td>
+                </tr>
+              </tbody>
+            </table>
+          </gr-list-view>
         `
       );
     });
+
+    test('render as admin', async () => {
+      await waitEventLoop();
+      element.isProjectOwner = true;
+      await element.updateComplete;
+      assert.shadowDom.equal(
+        element,
+        /* HTML */ `
+          <gr-list-view>
+            <table class="genericList" id="list">
+              <tbody>
+                <tr class="headerRow">
+                  <th class="topHeader">Name</th>
+                  <th class="topHeader">Description</th>
+                  <th class="topHeader">Applicability Expression</th>
+                  <th class="topHeader">Submittability Expression</th>
+                  <th class="topHeader">Override Expression</th>
+                  <th
+                    class="topHeader"
+                    title="Whether override is allowed in child projects"
+                  >
+                    Allow Override
+                  </th>
+                  <th class="topHeader"></th>
+                </tr>
+              </tbody>
+              <tbody id="submit-requirements">
+                <tr class="table">
+                  <td class="name">Verified</td>
+                  <td class="desc">
+                    CI result status for build and tests is passing
+                  </td>
+                  <td class="applicability"></td>
+                  <td class="submittability">
+                    label:Verified=MAX AND -label:Verified=MIN
+                  </td>
+                  <td class="override"></td>
+                  <td class="allowOverride"></td>
+                  <td class="actions">
+                  <gr-button
+                      aria-disabled="false"
+                      class="editBtn"
+                      link=""
+                      role="button"
+                      tabindex="0"
+                    >
+                      Edit
+                    </gr-button>
+                    <gr-button
+                      aria-disabled="false"
+                      class="deleteBtn"
+                      link=""
+                      role="button"
+                      tabindex="0"
+                    >
+                      Delete
+                    </gr-button>
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+          </gr-list-view>
+          <dialog id="createDialog" tabindex="-1">
+            <gr-dialog cancel-label="Cancel" confirm-label="Create" disabled="">
+              <div class="header" slot="header">Create Submit Requirement</div>
+              <div class="main" slot="main">
+                <div class="gr-form-styles">
+              <div id="form">
+                <section>
+                  <div class="title-flex">
+                    <span class="title">
+                      Name
+                    </span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <iron-input>
+                        <input
+                          id="name"
+                          required=""
+                          type="text"
+                        >
+                      </iron-input>
+                    </span>
+                  </div>
+                </section>
+                <section>
+                  <div class="title-flex">
+                    <span class="title">
+                      Description
+                    </span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <textarea
+                        id="description"
+                        placeholder="Optional"
+                      >
+                      </textarea>
+                    </span>
+                  </div>
+                </section>
+                <section>
+                  <div class="title-flex">
+                    <span class="title">
+                      Applicability Expression
+                    </span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <iron-input>
+                      <input
+                        id="applicability"
+                        placeholder="Optional"
+                        type="text"
+                      >
+                      </iron-input>
+                    </span>
+                  </div>
+                </section>
+                <section>
+                  <div class="title-flex">
+                    <span class="title">
+                      Submittability Expression
+                    </span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <iron-input>
+                      <input
+                        id="submittability"
+                        required=""
+                        type="text"
+                        >
+                      </iron-input>
+                    </span>
+                  </div>
+                </section>
+                <section>
+                  <div class="title-flex">
+                    <span class="title">
+                      Override Expression
+                    </span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <iron-input>
+                        <input
+                          id="override"
+                          placeholder="Optional"
+                          type="text"
+                        >
+                      </iron-input>
+                    </span>
+                  </div>
+                </section>
+                <section>
+                  <div class="title-flex">
+                    <span class="title">
+                      Allow Override in Child Projects
+                    </span>
+                  </div>
+                  <div class="value-flex">
+                    <span class="value">
+                      <gr-select id="allowOverride">
+                        <select>
+                          <option value="true">
+                            True
+                          </option>
+                          <option value="false">
+                            False
+                          </option>
+                        </select>
+                      </gr-select>
+                    </span>
+                  </div>
+                </section>
+              </div>
+            </gr-dialog>
+          </dialog>
+          <dialog
+        id="deleteDialog"
+        tabindex="-1"
+      >
+        <gr-dialog
+          cancel-label="Cancel"
+          confirm-label="Delete"
+        >
+          <div
+            class="header"
+            slot="header"
+          >
+            Delete Submit Requirement
+          </div>
+          <div
+            class="main"
+            slot="main"
+          >
+          Are you sure you want to delete the submit requirement
+            ""?
+          </div>
+        </gr-dialog>
+      </dialog>
+        `
+      );
+    });
+
+    test('open edit dialog', async () => {
+      await waitEventLoop();
+      element.isProjectOwner = true;
+      await element.updateComplete;
+
+      const editButton = queryAndAssert<GrButton>(element, '.editBtn');
+      editButton.click();
+      await element.updateComplete;
+
+      // Verify dialog is open and has correct title
+      const dialog = queryAndAssert<HTMLDialogElement>(
+        element,
+        '#createDialog'
+      );
+      assert.isTrue(dialog.open);
+
+      const dialogTitle = queryAndAssert<HTMLElement>(element, '.header');
+      assert.equal(dialogTitle.textContent?.trim(), 'Edit Submit Requirement');
+
+      // Verify form is populated with correct data
+      const nameInput = queryAndAssert<HTMLInputElement>(element, '#name');
+      assert.equal(nameInput.value, 'Verified');
+      assert.isTrue(nameInput.disabled);
+
+      const descriptionTextarea = queryAndAssert<HTMLTextAreaElement>(
+        element,
+        '#description'
+      );
+      assert.equal(
+        descriptionTextarea.value,
+        'CI result status for build and tests is passing'
+      );
+      assert.isFalse(descriptionTextarea.disabled);
+
+      const submittabilityInput = queryAndAssert<HTMLInputElement>(
+        element,
+        '#submittability'
+      );
+      assert.equal(
+        submittabilityInput.value,
+        'label:Verified=MAX AND -label:Verified=MIN'
+      );
+
+      // Verify save button is enabled
+      const saveButton = queryAndAssert<HTMLElement>(element, 'gr-dialog');
+      assert.isFalse(saveButton.hasAttribute('disabled'));
+    });
   });
 });
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
index 37b19b2..6473b39 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
@@ -20,7 +20,7 @@
 import {ColumnNames, ScrollMode} from '../../../constants/constants';
 import {
   getRequirements,
-  orderSubmitRequirements,
+  orderSubmitRequirementNames,
 } from '../../../utils/label-util';
 import {Key} from '../../../utils/dom-util';
 import {assertIsDefined, unique} from '../../../utils/common-util';
@@ -368,12 +368,16 @@
       return this.config?.submit_requirement_dashboard_columns;
     }
     const changes = sections.map(section => section.results).flat();
-    const labels = (changes ?? [])
-      .map(change => orderSubmitRequirements(getRequirements(change)))
-      .flat()
-      .map(requirement => requirement.name)
-      .filter(unique);
-    return labels.sort();
+    let labels: string[] = [];
+    if (this.config?.dashboard_show_all_labels) {
+      labels = changes.map(change => Object.keys(change.labels ?? {})).flat();
+    } else {
+      labels = changes
+        .map(change => getRequirements(change))
+        .flat()
+        .map(requirement => requirement.name);
+    }
+    return orderSubmitRequirementNames(labels.filter(unique));
   }
 
   private changesChanged() {
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.ts
index 30d3455..0c4397e 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.ts
@@ -6,7 +6,11 @@
 import * as sinon from 'sinon';
 import '../../../test/common-test-setup';
 import './gr-change-list';
-import {GrChangeList, computeRelativeIndex} from './gr-change-list';
+import {
+  ChangeListSection,
+  GrChangeList,
+  computeRelativeIndex,
+} from './gr-change-list';
 import {navigationToken} from '../../core/gr-navigation/gr-navigation';
 import {
   pressKey,
@@ -174,58 +178,87 @@
   });
 
   test('computed fields', () => {
-    assert.equal(
-      element.computeLabelNames([
-        {
+    const createTestSubmitReqs = (
+      labelLists: string[][]
+    ): ChangeListSection[] => {
+      let changeNumber = 0;
+      const sections: ChangeListSection[] = [];
+      for (const labelList of labelLists) {
+        sections.push({
           results: [
-            {...createChange(), _number: 0 as NumericChangeId, labels: {}},
+            {
+              ...createChange(),
+              _number: changeNumber++ as NumericChangeId,
+              submit_requirements: labelList.map(label => {
+                return {
+                  ...createSubmitRequirementResultInfo(),
+                  name: label,
+                };
+              }),
+            },
           ],
-        },
-      ]).length,
+        });
+      }
+      return sections;
+    };
+
+    assert.equal(
+      element.computeLabelNames(createTestSubmitReqs([[]])).length,
       0
     );
-    assert.equal(
-      element.computeLabelNames([
-        {
+    assert.deepEqual(
+      element.computeLabelNames(
+        createTestSubmitReqs([
+          ['Verified'],
+          ['Verified', 'Code-Review'],
+          ['Library-Compliance'],
+        ])
+      ),
+      ['Code-Review', 'Library-Compliance', 'Verified']
+    );
+
+    assert.deepEqual(
+      element.computeLabelNames(
+        createTestSubmitReqs([
+          ['Verified', 'A-Label'],
+          ['Verified', 'Code-Review'],
+        ])
+      ),
+      ['Code-Review', 'A-Label', 'Verified']
+    );
+  });
+
+  test('computed fields with all labels', () => {
+    const createTestLabels = (labelLists: string[][]): ChangeListSection[] => {
+      let changeNumber = 0;
+      const sections: ChangeListSection[] = [];
+      for (const labelList of labelLists) {
+        sections.push({
           results: [
             {
               ...createChange(),
-              _number: 0 as NumericChangeId,
-              submit_requirements: [
-                {
-                  ...createSubmitRequirementResultInfo(),
-                  name: 'Verified',
-                },
-              ],
-            },
-            {
-              ...createChange(),
-              _number: 1 as NumericChangeId,
-              submit_requirements: [
-                {
-                  ...createSubmitRequirementResultInfo(),
-                  name: 'Verified',
-                },
-                {
-                  ...createSubmitRequirementResultInfo(),
-                  name: 'Code-Review',
-                },
-              ],
-            },
-            {
-              ...createChange(),
-              _number: 2 as NumericChangeId,
-              submit_requirements: [
-                {
-                  ...createSubmitRequirementResultInfo(),
-                  name: 'Library-Compliance',
-                },
-              ],
+              _number: changeNumber++ as NumericChangeId,
+              labels: Object.fromEntries(labelList.map(label => [label, {}])),
             },
           ],
-        },
-      ]).length,
-      3
+        });
+      }
+      return sections;
+    };
+
+    element.config = {
+      ...createServerInfo(),
+      dashboard_show_all_labels: true,
+    };
+    assert.deepEqual(
+      element.computeLabelNames(
+        createTestLabels([
+          ['Verified', 'A-Label'],
+          ['Verified', 'Code-Review'],
+          ['Library-Compliance'],
+        ])
+      ),
+      ['Code-Review', 'A-Label', 'Library-Compliance', 'Verified']
     );
   });
 
@@ -434,7 +467,7 @@
         const elementClass = '.' + column.trim().toLowerCase();
         const section = queryAndAssert(element, 'gr-change-list-section');
         assert.isFalse(
-          queryAndAssert<HTMLElement>(section, elementClass)!.hidden
+          queryAndAssert<HTMLElement>(section, elementClass).hidden
         );
       }
     });
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index 6b1c925..12e9a43 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -1780,7 +1780,7 @@
       '/edit:publish',
       assertUIActionInfo(this.actions.publishEdit),
       false,
-      {notify: NotifyType.NONE}
+      {notify: NotifyType.OWNER_REVIEWERS}
     );
     this.sendPublishEditEvent();
   }
@@ -1852,7 +1852,7 @@
     action: UIActionInfo,
     revAction: boolean,
     payload?: RequestPayload,
-    toReport?: Object
+    toReport?: object
   ) {
     const cleanupFn = this.setLoadingOnButtonWithKey(action);
     this.reporting.reportInteraction(Interaction.CHANGE_ACTION_FIRED, {
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
index a26d37f8f..b9495cd 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
@@ -398,7 +398,7 @@
         )
       );
       assert.equal(
-        (element.revisionActions['plugin~action'] as UIActionInfo)!.__url,
+        (element.revisionActions['plugin~action'] as UIActionInfo).__url,
         'the-url'
       );
     });
@@ -416,7 +416,7 @@
         stub.calledWith(element.changeNum, undefined, '/plugin~action')
       );
       assert.equal(
-        (element.actions['plugin~action'] as UIActionInfo)!.__url,
+        (element.actions['plugin~action'] as UIActionInfo).__url,
         'the-url'
       );
     });
diff --git a/polygerrit-ui/app/elements/change/gr-change-summary/gr-summary-chip.ts b/polygerrit-ui/app/elements/change/gr-change-summary/gr-summary-chip.ts
index 5588f40..a61d41f 100644
--- a/polygerrit-ui/app/elements/change/gr-change-summary/gr-summary-chip.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-summary/gr-summary-chip.ts
@@ -35,7 +35,7 @@
   category?: CommentTabState;
 
   @property({type: Boolean})
-  clickable?: Boolean;
+  clickable?: boolean;
 
   private readonly reporting = getAppContext().reportingService;
 
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 147d012..63ecf8f 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -3,7 +3,7 @@
  * Copyright 2015 Google LLC
  * SPDX-License-Identifier: Apache-2.0
  */
-import {BehaviorSubject, combineLatest} from 'rxjs';
+import {BehaviorSubject} from 'rxjs';
 import '../gr-copy-links/gr-copy-links';
 import '@polymer/paper-tabs/paper-tabs';
 import '../../../styles/gr-a11y-styles';
@@ -34,7 +34,7 @@
 import '../../checks/gr-checks-tab';
 import {ChangeStarToggleStarDetail} from '../../shared/gr-change-star/gr-change-star';
 import {GrEditConstants} from '../../edit/gr-edit-constants';
-import {pluralize} from '../../../utils/string-util';
+import {pluralize, trimWithEllipsis} from '../../../utils/string-util';
 import {untilRendered, whenVisible} from '../../../utils/dom-util';
 import {navigationToken} from '../../core/gr-navigation/gr-navigation';
 import {ChangeStatus, Tab, DiffViewMode} from '../../../constants/constants';
@@ -66,13 +66,11 @@
   LabelNameToInfoMap,
   NumericChangeId,
   PARENT,
-  PatchSetNum,
   QuickLabelInfo,
   RevisionInfo,
   RevisionPatchSetNum,
   ServerInfo,
   UrlEncodedCommentId,
-  isRobot,
 } from '../../../types/common';
 import {FocusTarget, GrReplyDialog} from '../gr-reply-dialog/gr-reply-dialog';
 import {GrIncludedInDialog} from '../gr-included-in-dialog/gr-included-in-dialog';
@@ -166,8 +164,6 @@
 
 const PREFIX = '#message-';
 
-const ROBOT_COMMENTS_LIMIT = 10;
-
 const ReloadToastMessage = {
   NEWER_REVISION: 'A newer patch set has been uploaded',
   RESTORED: 'This change has been restored',
@@ -359,9 +355,6 @@
   @state()
   private pluginTabsContentEndpoints: string[] = [];
 
-  @state()
-  private currentRobotCommentsPatchSet?: PatchSetNum;
-
   /**
    * This can be a string only for plugin provided tabs.
    */
@@ -373,12 +366,6 @@
   unresolvedOnly = true;
 
   @state()
-  private showAllRobotComments = false;
-
-  @state()
-  private showRobotCommentsButton = false;
-
-  @state()
   draftCount = 0;
 
   private throttledToggleChangeStar?: (e: KeyboardEvent) => void;
@@ -386,10 +373,6 @@
   @state()
   private showChecksTab = false;
 
-  // visible for testing
-  @state()
-  showFindingsTab = false;
-
   @state()
   private isViewCurrent = false;
 
@@ -596,17 +579,6 @@
     );
     subscribe(
       this,
-      () =>
-        combineLatest([
-          this.getConfigModel().enableRobotComments$,
-          this.getCommentsModel().robotCommentCount$,
-        ]),
-      ([enableRobotComments, count]) => {
-        this.showFindingsTab = enableRobotComments && count > 0;
-      }
-    );
-    subscribe(
-      this,
       () => this.getViewModel().childView$,
       childView => {
         this.isViewCurrent = childView === ChangeChildView.OVERVIEW;
@@ -1131,9 +1103,6 @@
         .patch-set-dropdown {
           margin: var(--spacing-m) 0 0 var(--spacing-m);
         }
-        .show-robot-comments {
-          margin: var(--spacing-m);
-        }
         .tabContent gr-thread-list::part(threads) {
           padding: var(--spacing-l);
         }
@@ -1245,7 +1214,9 @@
           >${this.change?._number}</a
         >
       </gr-button>
-      <span class="headerSubject">${this.change?.subject}</span>
+      <div class="headerSubject">
+        ${trimWithEllipsis(this.change?.subject, 80)}
+      </div>
       <gr-copy-clipboard
         class="changeCopyClipboard"
         hideInput=""
@@ -1429,14 +1400,6 @@
             </paper-tab>
           `
         )}
-        ${when(
-          this.showFindingsTab,
-          () => html`
-            <paper-tab data-name=${Tab.FINDINGS} @click=${this.onPaperTabClick}>
-              <span>Findings</span>
-            </paper-tab>
-          `
-        )}
       </paper-tabs>
     `;
   }
@@ -1445,8 +1408,7 @@
     return html`
       <section class="tabContent">
         ${this.renderFilesTab()} ${this.renderCommentsTab()}
-        ${this.renderChecksTab()} ${this.renderFindingsTab()}
-        ${this.renderPluginTab()}
+        ${this.renderChecksTab()} ${this.renderPluginTab()}
       </section>
     `;
   }
@@ -1501,7 +1463,6 @@
       <gr-thread-list
         .threads=${this.commentThreads}
         .commentTabState=${this.tabState}
-        only-show-robot-comments-with-human-reply
         .unresolvedOnly=${this.unresolvedOnly}
         .scrollCommentId=${this.scrollCommentId}
         show-comment-context
@@ -1517,36 +1478,6 @@
     `;
   }
 
-  private renderFindingsTab() {
-    if (this.activeTab !== Tab.FINDINGS) return nothing;
-    if (!this.showFindingsTab) return nothing;
-    const robotCommentThreads = this.computeRobotCommentThreads();
-    const robotCommentsPatchSetDropdownItems =
-      this.computeRobotCommentsPatchSetDropdownItems();
-    return html`
-      <gr-dropdown-list
-        class="patch-set-dropdown"
-        .items=${robotCommentsPatchSetDropdownItems}
-        .value=${this.currentRobotCommentsPatchSet}
-        @value-change=${this.handleRobotCommentPatchSetChanged}
-      >
-      </gr-dropdown-list>
-      <gr-thread-list .threads=${robotCommentThreads} hide-dropdown>
-      </gr-thread-list>
-      ${when(
-        this.showRobotCommentsButton,
-        () => html`
-          <gr-button
-            class="show-robot-comments"
-            @click=${this.toggleShowRobotComments}
-          >
-            ${this.showAllRobotComments ? 'Show Less' : 'Show More'}
-          </gr-button>
-        `
-      )}
-    `;
-  }
-
   private renderPluginTab() {
     const i = this.pluginTabsHeaderEndpoints.findIndex(
       t => this.activeTab === t
@@ -1753,76 +1684,6 @@
     return false;
   }
 
-  // Private but used in tests.
-  robotCommentCountPerPatchSet(threads: CommentThread[]) {
-    return threads.reduce((robotCommentCountMap, thread) => {
-      const comments = thread.comments;
-      const robotCommentsCount = comments.reduce(
-        (acc, comment) => (isRobot(comment) ? acc + 1 : acc),
-        0
-      );
-      if (comments[0].patch_set)
-        robotCommentCountMap[`${comments[0].patch_set}`] =
-          (robotCommentCountMap[`${comments[0].patch_set}`] || 0) +
-          robotCommentsCount;
-      return robotCommentCountMap;
-    }, {} as {[patchset: string]: number});
-  }
-
-  // Private but used in tests.
-  computeText(
-    patch: RevisionInfo | EditRevisionInfo,
-    commentThreads: CommentThread[]
-  ) {
-    const commentCount = this.robotCommentCountPerPatchSet(commentThreads);
-    const commentCnt = commentCount[patch._number] || 0;
-    if (commentCnt === 0) return `Patchset ${patch._number}`;
-    return `Patchset ${patch._number} (${pluralize(commentCnt, 'finding')})`;
-  }
-
-  private computeRobotCommentsPatchSetDropdownItems() {
-    if (!this.change || !this.commentThreads || !this.change.revisions)
-      return [];
-
-    return Object.values(this.change.revisions)
-      .filter(patch => patch._number !== EDIT)
-      .map(patch => {
-        return {
-          text: this.computeText(patch, this.commentThreads!),
-          value: patch._number,
-        };
-      })
-      .sort((a, b) => (b.value as number) - (a.value as number));
-  }
-
-  private handleRobotCommentPatchSetChanged(e: CustomEvent<{value: string}>) {
-    const patchSet = Number(e.detail.value) as PatchSetNum;
-    if (patchSet === this.currentRobotCommentsPatchSet) return;
-    this.currentRobotCommentsPatchSet = patchSet;
-  }
-
-  private toggleShowRobotComments() {
-    this.showAllRobotComments = !this.showAllRobotComments;
-  }
-
-  // Private but used in tests.
-  computeRobotCommentThreads() {
-    if (!this.commentThreads || !this.currentRobotCommentsPatchSet) return [];
-    const threads = this.commentThreads.filter(thread => {
-      const comments = thread.comments || [];
-      return (
-        comments.length &&
-        isRobot(comments[0]) &&
-        comments[0].patch_set === this.currentRobotCommentsPatchSet
-      );
-    });
-    this.showRobotCommentsButton = threads.length > ROBOT_COMMENTS_LIMIT;
-    return threads.slice(
-      0,
-      this.showAllRobotComments ? undefined : ROBOT_COMMENTS_LIMIT
-    );
-  }
-
   private computeTotalCommentCounts() {
     const unresolvedCount = this.change?.unresolved_comment_count ?? 0;
     const draftCount = this.draftCount;
@@ -2012,14 +1873,6 @@
     this.allPatchSets = computeAllPatchSets(this.change);
     if (!this.change) return;
     this.labelsChanged(oldChange?.labels, this.change.labels);
-    if (
-      this.change.current_revision &&
-      this.change.revisions &&
-      this.change.revisions[this.change.current_revision]
-    ) {
-      this.currentRobotCommentsPatchSet =
-        this.change.revisions[this.change.current_revision]._number;
-    }
   }
 
   /**
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index 1ffe720..d075ea6 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -50,8 +50,6 @@
   NumericChangeId,
   PARENT,
   RevisionPatchSetNum,
-  RobotId,
-  RobotCommentInfo,
   Timestamp,
   UrlEncodedCommentId,
   RepoName,
@@ -72,7 +70,6 @@
 import {assertIsDefined} from '../../../utils/common-util';
 import {fixture, html, assert} from '@open-wc/testing';
 import {Modifier} from '../../../utils/dom-util';
-import {GrButton} from '../../shared/gr-button/gr-button';
 import {GrCopyLinks} from '../gr-copy-links/gr-copy-links';
 import {
   ChangeChildView,
@@ -90,8 +87,6 @@
   let userModel: UserModel;
   let changeModel: ChangeModel;
 
-  const ROBOT_COMMENTS_LIMIT = 10;
-
   // TODO: should have a mock service to generate VALID fake data
   const THREADS: CommentThread[] = [
     {
@@ -103,21 +98,6 @@
             name: 'user',
             username: 'user',
           },
-          patch_set: 2 as RevisionPatchSetNum,
-          robot_id: 'rb1' as RobotId,
-          id: 'ecf0b9fa_fe1a5f62' as UrlEncodedCommentId,
-          line: 5,
-          updated: '2018-02-08 18:49:18.000000000' as Timestamp,
-          message: 'test',
-          unresolved: true,
-        },
-        {
-          path: '/COMMIT_MSG',
-          author: {
-            _account_id: 1000000 as AccountId,
-            name: 'user',
-            username: 'user',
-          },
           patch_set: 4 as RevisionPatchSetNum,
           id: 'ecf0b9fa_fe1a5f62_1' as UrlEncodedCommentId,
           line: 5,
@@ -146,21 +126,6 @@
     {
       comments: [
         {
-          path: '/COMMIT_MSG',
-          author: {
-            _account_id: 1000000 as AccountId,
-            name: 'user',
-            username: 'user',
-          },
-          patch_set: 3 as RevisionPatchSetNum,
-          id: 'ecf0b9fa_fe5f62' as UrlEncodedCommentId,
-          robot_id: 'rb2' as RobotId,
-          line: 5,
-          updated: '2018-02-08 18:49:18.000000000' as Timestamp,
-          message: 'test',
-          unresolved: true,
-        },
-        {
           path: 'test.txt',
           author: {
             _account_id: 1000000 as AccountId,
@@ -247,23 +212,7 @@
       commentSide: CommentSide.REVISION,
     },
     {
-      comments: [
-        {
-          path: '/COMMIT_MSG',
-          author: {
-            _account_id: 1000000 as AccountId,
-            name: 'user',
-            username: 'user',
-          },
-          patch_set: 4 as RevisionPatchSetNum,
-          id: 'rc1' as UrlEncodedCommentId,
-          line: 5,
-          updated: '2019-02-08 18:49:18.000000000' as Timestamp,
-          message: 'test',
-          unresolved: true,
-          robot_id: 'rc1' as RobotId,
-        },
-      ],
+      comments: [],
       patchNum: 4 as RevisionPatchSetNum,
       path: '/COMMIT_MSG',
       line: 5,
@@ -280,21 +229,6 @@
             username: 'user',
           },
           patch_set: 4 as RevisionPatchSetNum,
-          id: 'rc2' as UrlEncodedCommentId,
-          line: 5,
-          updated: '2019-03-08 18:49:18.000000000' as Timestamp,
-          message: 'test',
-          unresolved: true,
-          robot_id: 'rc2' as RobotId,
-        },
-        {
-          path: '/COMMIT_MSG',
-          author: {
-            _account_id: 1000000 as AccountId,
-            name: 'user',
-            username: 'user',
-          },
-          patch_set: 4 as RevisionPatchSetNum,
           id: 'c2_1' as UrlEncodedCommentId,
           line: 5,
           updated: '2019-03-08 18:49:18.000000000' as Timestamp,
@@ -332,7 +266,6 @@
       Promise.resolve(createAccountDetailWithId(5))
     );
     stubRestApi('getDiffComments').returns(Promise.resolve({}));
-    stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
     stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
 
     window.Gerrit.install(
@@ -391,7 +324,7 @@
                   ><gr-change-star id="changeStar"> </gr-change-star>
                   <a aria-label="Change undefined" class="changeNumber"> </a>
                 </gr-button>
-                <span class="headerSubject"> </span>
+                <div class="headerSubject"></div>
                 <gr-copy-clipboard
                   class="changeCopyClipboard"
                   hideinput=""
@@ -965,112 +898,6 @@
     });
   });
 
-  suite('Findings robot-comment tab', () => {
-    setup(async () => {
-      element.changeNum = TEST_NUMERIC_CHANGE_ID;
-      element.change = {
-        ...createChangeViewChange(),
-        revisions: {
-          rev2: createRevision(2),
-          rev1: createRevision(1),
-          rev13: createRevision(13),
-          rev3: createRevision(3),
-          rev4: createRevision(4),
-        },
-        current_revision: 'rev4' as CommitId,
-      };
-      element.commentThreads = THREADS;
-      element.showFindingsTab = true;
-      await element.updateComplete;
-      const paperTabs = element.shadowRoot!.querySelector('#tabs')!;
-      const tabs = paperTabs.querySelectorAll('paper-tab');
-      assert.isTrue(tabs.length > 3);
-      assert.equal(tabs[3].dataset.name, 'findings');
-      tabs[3].click();
-      await element.updateComplete;
-    });
-
-    test('robot comments count per patchset', () => {
-      const count = element.robotCommentCountPerPatchSet(THREADS);
-      const expectedCount = {
-        2: 1,
-        3: 1,
-        4: 2,
-      };
-      assert.deepEqual(count, expectedCount);
-      assert.equal(
-        element.computeText(createRevision(2), THREADS),
-        'Patchset 2 (1 finding)'
-      );
-      assert.equal(
-        element.computeText(createRevision(4), THREADS),
-        'Patchset 4 (2 findings)'
-      );
-      assert.equal(
-        element.computeText(createRevision(5), THREADS),
-        'Patchset 5'
-      );
-    });
-
-    test('only robot comments are rendered', () => {
-      assert.equal(element.computeRobotCommentThreads().length, 2);
-      assert.equal(
-        (
-          element.computeRobotCommentThreads()[0]
-            .comments[0] as RobotCommentInfo
-        ).robot_id,
-        'rc1'
-      );
-      assert.equal(
-        (
-          element.computeRobotCommentThreads()[1]
-            .comments[0] as RobotCommentInfo
-        ).robot_id,
-        'rc2'
-      );
-    });
-
-    test('changing patchsets resets robot comments', async () => {
-      assertIsDefined(element.change);
-      const newChange = {...element.change};
-      newChange.current_revision = 'rev3' as CommitId;
-      element.change = newChange;
-      await element.updateComplete;
-      assert.equal(element.computeRobotCommentThreads().length, 1);
-    });
-
-    test('Show more button is hidden', () => {
-      assert.isNull(element.shadowRoot!.querySelector('.show-robot-comments'));
-    });
-
-    suite('robot comments show more button', () => {
-      setup(async () => {
-        const arr = [];
-        for (let i = 0; i <= 30; i++) {
-          arr.push(...THREADS);
-        }
-        element.commentThreads = arr;
-        await element.updateComplete;
-      });
-
-      test('Show more button is rendered', () => {
-        assert.isOk(element.shadowRoot!.querySelector('.show-robot-comments'));
-        assert.equal(
-          element.computeRobotCommentThreads().length,
-          ROBOT_COMMENTS_LIMIT
-        );
-      });
-
-      test('Clicking show more button renders all comments', async () => {
-        element
-          .shadowRoot!.querySelector<GrButton>('.show-robot-comments')!
-          .click();
-        await element.updateComplete;
-        assert.equal(element.computeRobotCommentThreads().length, 62);
-      });
-    });
-  });
-
   test('reply button is a login button when logged out', async () => {
     assertIsDefined(element.replyBtn);
     element.loggedIn = false;
@@ -1536,7 +1363,7 @@
     const stub = sinon.stub(element, 'handleToggleStar');
 
     const changeStar = queryAndAssert<GrChangeStar>(element, '#changeStar');
-    queryAndAssert<HTMLButtonElement>(changeStar, 'button')!.click();
+    queryAndAssert<HTMLButtonElement>(changeStar, 'button').click();
     assert.isTrue(stub.called);
   });
 
diff --git a/polygerrit-ui/app/elements/change/gr-comments-summary/gr-comments-summary.ts b/polygerrit-ui/app/elements/change/gr-comments-summary/gr-comments-summary.ts
index 9123cd6..ac5c7b1 100644
--- a/polygerrit-ui/app/elements/change/gr-comments-summary/gr-comments-summary.ts
+++ b/polygerrit-ui/app/elements/change/gr-comments-summary/gr-comments-summary.ts
@@ -10,9 +10,7 @@
 import {customElement, property, state} from 'lit/decorators.js';
 import {
   getFirstComment,
-  hasHumanReply,
   isResolved,
-  isRobotThread,
   isUnresolved,
 } from '../../../utils/comment-util';
 import {pluralize} from '../../../utils/string-util';
@@ -96,9 +94,7 @@
   }
 
   override render() {
-    const commentThreads =
-      this.commentThreads?.filter(t => !isRobotThread(t) || hasHumanReply(t)) ??
-      [];
+    const commentThreads = this.commentThreads ?? [];
     const countResolvedComments = commentThreads.filter(isResolved).length;
     const unresolvedThreads = commentThreads.filter(isUnresolved);
     const countUnresolvedComments = unresolvedThreads.length;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog_test.ts
index 61cc227..d46a57c 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog_test.ts
@@ -57,7 +57,7 @@
     queryAndAssert<GrButton>(
       queryAndAssert<GrDialog>(element, 'gr-dialog'),
       'gr-button#cancel'
-    )!.click();
+    ).click();
     await element.updateComplete;
 
     assert.isTrue(cancelHandler.called);
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
index b6fba85..0f8d045 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
@@ -34,6 +34,7 @@
 } from '../../../constants/constants';
 import {subscribe} from '../../lit/subscription-controller';
 import {fire, fireNoBubble} from '../../../utils/event-util';
+import {trimWithEllipsis} from '../../../utils/string-util';
 import {css, html, LitElement, PropertyValues} from 'lit';
 import {sharedStyles} from '../../../styles/shared-styles';
 import {choose} from 'lit/directives/choose.js';
@@ -414,7 +415,9 @@
                 <td><span> ${this.getChangeId(item)} </span></td>
                 <td><span> ${item.status} </span></td>
                 <td>
-                  <span> ${this.getTrimmedChangeSubject(item.subject)} </span>
+                  <span>
+                    ${trimWithEllipsis(item.subject, CHANGE_SUBJECT_LIMIT)}
+                  </span>
                 </td>
                 <td><span> ${item.project} </span></td>
                 <td>
@@ -523,12 +526,6 @@
     return change.change_id.substring(0, 10);
   }
 
-  private getTrimmedChangeSubject(subject: string) {
-    if (!subject) return '';
-    if (subject.length < CHANGE_SUBJECT_LIMIT) return subject;
-    return subject.substring(0, CHANGE_SUBJECT_LIMIT) + '...';
-  }
-
   private computeCancelLabel() {
     const isRunningChange = Object.values(this.statuses).some(
       v => v.status === ProgressStatus.RUNNING
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.ts
index 8bcd053..db135df 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.ts
@@ -97,7 +97,6 @@
   suite('basic tests', async () => {
     setup(async () => {
       stubRestApi('getDiffComments').returns(Promise.resolve({}));
-      stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
       stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
       stubRestApi('getAccountCapabilities').returns(Promise.resolve({}));
       stubElement('gr-diff-host', 'reload').callsFake(() => Promise.resolve());
@@ -2010,7 +2009,6 @@
     setup(async () => {
       stubRestApi('getPreferences').returns(Promise.resolve(undefined));
       stubRestApi('getDiffComments').returns(Promise.resolve({}));
-      stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
       stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
       stubRestApi('getDiff').callsFake(() => Promise.resolve(createDiff()));
       stubElement('gr-diff-host', 'prefetchDiff').callsFake(() => {});
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.ts
index 3851255..d3692ed 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.ts
@@ -92,7 +92,7 @@
   });
 
   test('computeGroups with .bindValue', async () => {
-    queryAndAssert<IronInputElement>(element, '#filterInput')!.bindValue =
+    queryAndAssert<IronInputElement>(element, '#filterInput').bindValue =
       'stable-3.2';
     element.includedIn = {branches: [], tags: []} as IncludedInInfo;
     element.includedIn.branches.push(
diff --git a/polygerrit-ui/app/elements/change/gr-message-scores/gr-message-scores.ts b/polygerrit-ui/app/elements/change/gr-message-scores/gr-message-scores.ts
index 09ca036..60fb1df 100644
--- a/polygerrit-ui/app/elements/change/gr-message-scores/gr-message-scores.ts
+++ b/polygerrit-ui/app/elements/change/gr-message-scores/gr-message-scores.ts
@@ -4,9 +4,10 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 import '../gr-trigger-vote/gr-trigger-vote';
-import {LitElement, css, html} from 'lit';
-import {customElement, property} from 'lit/decorators.js';
-import {ChangeInfo} from '../../../api/rest-api';
+import '../../checks/gr-checks-chip-for-label';
+import {LitElement, css, html, nothing} from 'lit';
+import {customElement, property, state} from 'lit/decorators.js';
+import {ChangeInfo, PatchSetNumber} from '../../../api/rest-api';
 import {
   LabelExtreme,
   PATCH_SET_PREFIX_PATTERN,
@@ -14,6 +15,10 @@
 import {hasOwnProperty} from '../../../utils/common-util';
 import {getTriggerVotes} from '../../../utils/label-util';
 import {ChangeMessage} from '../../../types/common';
+import {CheckRun} from '../../../api/checks';
+import {subscribe} from '../../lit/subscription-controller';
+import {resolve} from '../../../models/dependency';
+import {changeModelToken} from '../../../models/change/change-model';
 
 const VOTE_RESET_TEXT = '0 (vote reset)';
 
@@ -36,6 +41,10 @@
   @property({type: Object})
   change?: ChangeInfo;
 
+  @state() runs: CheckRun[] = [];
+
+  @state() latestPatchNum?: PatchSetNumber;
+
   static override get styles() {
     return css`
       .score,
@@ -86,9 +95,26 @@
           min-width: 0px;
         }
       }
+
+      gr-checks-chip-for-label {
+        /* .checksChip has top: 2px, this is canceling it */
+        position: relative;
+        top: -2px;
+      }
     `;
   }
 
+  private readonly getChangeModel = resolve(this, changeModelToken);
+
+  constructor() {
+    super();
+    subscribe(
+      this,
+      () => this.getChangeModel().latestPatchNum$,
+      x => (this.latestPatchNum = x)
+    );
+  }
+
   override render() {
     const scores = this._getScores(this.message, this.labelExtremes);
     const triggerVotes = getTriggerVotes(this.change);
@@ -113,10 +139,22 @@
       </gr-trigger-vote>`;
     }
     return html`<span
-      class="score ${this._computeScoreClass(score, this.labelExtremes)}"
-    >
-      ${score.label} ${score.value}
-    </span>`;
+        class="score ${this._computeScoreClass(score, this.labelExtremes)}"
+      >
+        ${score.label} ${score.value} </span
+      >${this.renderChecks(score)}`;
+  }
+
+  renderChecks(score: Score) {
+    const labelName = score.label;
+    if (!labelName) return nothing;
+    if (Number(score.value) >= 0) return nothing;
+    if (this.latestPatchNum !== this.message?._revision_number) return nothing;
+
+    return html`<gr-checks-chip-for-label
+      .labels=${[labelName]}
+      .showRunning=${false}
+    ></gr-checks-chip-for-label>`;
   }
 
   _computeScoreClass(score?: Score, labelExtremes?: LabelExtreme) {
diff --git a/polygerrit-ui/app/elements/change/gr-message-scores/gr-message-scores_test.ts b/polygerrit-ui/app/elements/change/gr-message-scores/gr-message-scores_test.ts
index a757b37..63a7f17 100644
--- a/polygerrit-ui/app/elements/change/gr-message-scores/gr-message-scores_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-message-scores/gr-message-scores_test.ts
@@ -13,6 +13,7 @@
 import {queryAll, stubFlags} from '../../../test/test-utils';
 import {GrMessageScores} from './gr-message-scores';
 import {fixture, html, assert} from '@open-wc/testing';
+import {PatchSetNumber} from '../../../api/rest-api';
 
 suite('gr-message-score tests', () => {
   let element: GrMessageScores;
@@ -40,6 +41,7 @@
       /* HTML */ `
         <span class="max positive score"> Verified +1 </span>
         <span class="min negative score"> Code-Review -2 </span>
+        <gr-checks-chip-for-label></gr-checks-chip-for-label>
         <span class="positive score"> Trybot-Label3 +1 </span>
       `
     );
@@ -192,4 +194,28 @@
       `
     );
   });
+
+  test('shows checks chip', async () => {
+    element.message = {
+      ...createChangeMessage(),
+      author: {},
+      expanded: false,
+      message: 'Patch Set 1: Verified-1',
+      _revision_number: 1 as PatchSetNumber,
+    };
+    element.labelExtremes = {
+      Verified: {max: 1, min: -1},
+    };
+    element.latestPatchNum = 1 as PatchSetNumber;
+
+    await element.updateComplete;
+
+    assert.shadowDom.equal(
+      element,
+      /* HTML */ `
+        <span class="min negative score"> Verified -1 </span
+        ><gr-checks-chip-for-label></gr-checks-chip-for-label>
+      `
+    );
+  });
 });
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
index 3c2b792..fb8e905 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
@@ -20,7 +20,6 @@
   NumericChangeId,
   PatchSetNum,
   VotingRangeInfo,
-  isRobot,
   PatchSetNumber,
 } from '../../../types/common';
 import {GrMessage, MessageAnchorTapDetail} from '../gr-message/gr-message';
@@ -102,27 +101,18 @@
  * a message is initially hidden or not, see isImportant(). So we are applying
  * some "magic" rules here in order to hide exactly the right messages.
  *
- * 1. If a message does not have a tag, but is associated with robot comments,
- * then it gets a tag.
- *
- * 2. Use the same tag for some of Gerrit's standard events, if they should be
+ * 1. Use the same tag for some of Gerrit's standard events, if they should be
  * considered one group, e.g. normal and wip patchset uploads.
  *
- * 3. Everything beyond the ~ character is cut off from the tag. That gives
+ * 2. Everything beyond the ~ character is cut off from the tag. That gives
  * tools control over which messages will be hidden.
  *
- * 4. (Non-WIP) patchset uploads get a separate tag when they invalidate any
+ * 3. (Non-WIP) patchset uploads get a separate tag when they invalidate any
  * votes.
  */
 function computeTag(message: CombinedMessage) {
   if (!message.tag) {
-    const threads = message.commentThreads || [];
-    const messageId = getMessageId(message);
-    const comments = threads.map(t =>
-      t.comments.find(c => c.change_message_id === messageId)
-    );
-    const hasRobotComments = comments.some(isRobot);
-    return hasRobotComments ? 'autogenerated:has-robot-comments' : undefined;
+    return undefined;
   }
 
   if (message.tag === MessageTag.TAG_NEW_PATCHSET) {
@@ -388,7 +378,7 @@
           .commentThreads=${message.commentThreads}
           @message-anchor-tap=${this.handleAnchorClick}
           .labelExtremes=${labelExtremes}
-          data-message-id=${ifDefined(getMessageId(message) as String)}
+          data-message-id=${ifDefined(getMessageId(message) as string)}
         ></gr-message>`
       )}`;
   }
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.ts b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.ts
index d4c7b63..2bce8a4 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.ts
@@ -137,7 +137,6 @@
     setup(async () => {
       stubRestApi('getLoggedIn').returns(Promise.resolve(false));
       stubRestApi('getDiffComments').returns(Promise.resolve(comments));
-      stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
       stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
 
       messages = generateRandomMessages(3);
@@ -384,21 +383,6 @@
       assert.equal(TEST_ONLY.computeTag(m), 'something');
     });
 
-    test('updateTag with robot comments', () => {
-      const m = randomMessage();
-      (m as any).commentThreads = [
-        {
-          comments: [
-            {
-              robot_id: 'id314',
-              change_message_id: m.id,
-            },
-          ],
-        },
-      ];
-      assert.notEqual(TEST_ONLY.computeTag(m), undefined);
-    });
-
     test('setRevisionNumber nothing to change', () => {
       const m1 = randomMessage();
       const m2 = randomMessage();
@@ -546,7 +530,6 @@
     setup(async () => {
       stubRestApi('getLoggedIn').returns(Promise.resolve(false));
       stubRestApi('getDiffComments').returns(Promise.resolve({}));
-      stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
       stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
 
       messages = [
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts
index 3b76eda..999f657 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts
@@ -2438,7 +2438,7 @@
   test('isSendDisabled_existingVote', async () => {
     const account = createAccountWithId();
     (
-      element.change!.labels![StandardLabels.CODE_REVIEW]! as DetailedLabelInfo
+      element.change!.labels![StandardLabels.CODE_REVIEW] as DetailedLabelInfo
     ).all = [account];
     element.canBeStarted = false;
     element.draftCommentThreads = [{...createCommentThread([createComment()])}];
@@ -2849,7 +2849,6 @@
       };
       commentsModel.setState({
         comments: {},
-        robotComments: {},
         drafts: {
           a: [draft],
         },
@@ -2884,7 +2883,6 @@
       };
       commentsModel.setState({
         comments: {},
-        robotComments: {},
         drafts: {
           a: [draft],
         },
@@ -2924,7 +2922,6 @@
       };
       commentsModel.setState({
         comments: {},
-        robotComments: {},
         drafts: {
           a: [draft],
         },
@@ -2984,7 +2981,6 @@
 
       commentsModel.setState({
         comments: {},
-        robotComments: {},
         drafts: {
           a: [
             {
@@ -3021,7 +3017,6 @@
       stubRestApi('getAccountDetails').returns(Promise.resolve(account));
       commentsModel.setState({
         comments: {},
-        robotComments: {},
         drafts: {
           a: [
             {
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
index d950941..61e569a 100644
--- a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
@@ -10,6 +10,7 @@
 import '../gr-change-summary/gr-change-summary';
 import '../../shared/gr-limited-text/gr-limited-text';
 import '../../shared/gr-vote-chip/gr-vote-chip';
+import '../../checks/gr-checks-chip-for-label';
 import {LitElement, css, html, TemplateResult, nothing} from 'lit';
 import {customElement, property, state} from 'lit/decorators.js';
 import {ParsedChangeInfo} from '../../../types/types';
@@ -36,16 +37,15 @@
 } from '../../../utils/label-util';
 import {fontStyles} from '../../../styles/gr-font-styles';
 import {capitalizeFirstLetter, charsOnly} from '../../../utils/string-util';
-import {subscribe} from '../../lit/subscription-controller';
-import {CheckRun} from '../../../models/checks/checks-model';
-import {getResultsOf, hasResultsOf} from '../../../models/checks/checks-util';
-import {Category, RunStatus} from '../../../api/checks';
-import {fireShowTab} from '../../../utils/event-util';
-import {Tab} from '../../../constants/constants';
 import {submitRequirementsStyles} from '../../../styles/gr-submit-requirements-styles';
 import {resolve} from '../../../models/dependency';
-import {checksModelToken} from '../../../models/checks/checks-model';
+import {CheckRun, checksModelToken} from '../../../models/checks/checks-model';
 import {map} from 'lit/directives/map.js';
+import {
+  countErrorRunsForLabel,
+  countRunningRunsForLabel,
+} from '../../checks/gr-checks-util';
+import {subscribe} from '../../lit/subscription-controller';
 
 /**
  * @attr {Boolean} suppress-title - hide titles, currently for hovercard view
@@ -125,7 +125,7 @@
         gr-vote-chip {
           margin-right: var(--spacing-s);
         }
-        gr-checks-chip {
+        gr-checks-chip-for-label {
           /* .checksChip has top: 2px, this is canceling it */
           margin-top: -2px;
         }
@@ -373,73 +373,43 @@
   }
 
   renderChecks(requirement: SubmitRequirementResultInfo, labelName?: string) {
-    const requirementLabels = extractAssociatedLabels(requirement);
-    const errorRuns = this.runs
-      .filter(run => hasResultsOf(run, Category.ERROR))
-      .filter(run => {
-        if (labelName) {
-          return labelName === run.labelName;
-        } else {
-          return run.labelName && requirementLabels.includes(run.labelName);
-        }
-      });
-    const errorRunsCount = errorRuns.reduce(
-      (sum, run) => sum + getResultsOf(run, Category.ERROR).length,
-      0
+    // This method includes preliminary checks before rendering the
+    // <gr-checks-chip-for-label> component. These checks are necessary
+    // because:
+    // 1. We only want to display the checks chip for specific conditions
+    //    relevant to message scores (e.g., negative scores on the latest
+    //    patchset for which the message was posted).
+    // 2. It's programmatically difficult for a parent component to know if a
+    //    child Lit component (like <gr-checks-chip-for-label>) will internally
+    //    render 'nothing'. If the child component were rendered unconditionally
+    //    and then its own logic led it to render 'nothing', we might still
+    //    have an empty custom element in the DOM or face challenges in
+    //    conditionally rendering alternative UI elements that depend on the
+    //    child's visibility
+    // These upfront checks ensure that <gr-checks-chip-for-label> is only
+    // instantiated and rendered when it's genuinely appropriate and likely
+    // to display meaningful information, avoiding an empty or superfluous element.
+    const targetLabels = labelName
+      ? [labelName]
+      : requirement
+      ? extractAssociatedLabels(requirement)
+      : [];
+
+    // If there are no labels to filter by, then no checks can be associated.
+    if (targetLabels.length === 0) return undefined;
+
+    const {errorRunsCount} = countErrorRunsForLabel(this.runs, targetLabels);
+    const {runningRunsCount} = countRunningRunsForLabel(
+      this.runs,
+      targetLabels
     );
-    if (errorRunsCount > 0) {
-      return this.renderChecksCategoryChip(
-        errorRuns,
-        errorRunsCount,
-        Category.ERROR
-      );
-    }
-    const runningRuns = this.runs
-      .filter(r => r.isLatestAttempt)
-      .filter(
-        r => r.status === RunStatus.RUNNING || r.status === RunStatus.SCHEDULED
-      )
-      .filter(run => {
-        if (labelName) {
-          return labelName === run.labelName;
-        } else {
-          return run.labelName && requirementLabels.includes(run.labelName);
-        }
-      });
 
-    const runningRunsCount = runningRuns.length;
-    if (runningRunsCount > 0) {
-      return this.renderChecksCategoryChip(
-        runningRuns,
-        runningRunsCount,
-        RunStatus.RUNNING
-      );
-    }
-    return;
-  }
-
-  renderChecksCategoryChip(
-    runs: CheckRun[],
-    runsCount: Number,
-    category: Category | RunStatus
-  ) {
-    if (runsCount === 0) return;
-    const links = [];
-    if (runs.length === 1 && runs[0].statusLink) {
-      links.push(runs[0].statusLink);
-    }
-    return html`<gr-checks-chip
-      .text=${`${runsCount}`}
-      .links=${links}
-      .statusOrCategory=${category}
-      @click=${() => {
-        fireShowTab(this, Tab.CHECKS, false, {
-          checksTab: {
-            statusOrCategory: category,
-          },
-        });
-      }}
-    ></gr-checks-chip>`;
+    if (errorRunsCount <= 0 && runningRunsCount <= 0) return undefined;
+    return html`<gr-checks-chip-for-label
+      .requirement=${requirement}
+      .labels=${targetLabels}
+      .showRunning=${true}
+    ></gr-checks-chip-for-label>`;
   }
 
   renderTriggerVotes() {
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts
index a5a336c..47d1800 100644
--- a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts
@@ -157,7 +157,7 @@
 
     test('without label to vote on', async () => {
       const modifiedChange = {...change};
-      modifiedChange.submit_requirements![0]!.submittability_expression_result.expression =
+      modifiedChange.submit_requirements![0].submittability_expression_result.expression =
         'hasfooter:"Release-Notes"';
       element.change = modifiedChange;
       await element.updateComplete;
@@ -185,7 +185,7 @@
             <div class="votes">
               <div class="votes-line">
                 <gr-vote-chip> </gr-vote-chip>
-                <gr-checks-chip> </gr-checks-chip>
+                <gr-checks-chip-for-label> </gr-checks-chip-for-label>
               </div>
             </div>
           </div>
@@ -211,7 +211,7 @@
             <div class="votes">
               <div class="votes-line">
                 <gr-vote-chip> </gr-vote-chip>
-                <gr-checks-chip> </gr-checks-chip>
+                <gr-checks-chip-for-label> </gr-checks-chip-for-label>
               </div>
             </div>
           </div>
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
index 86bf1b2..8906426 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
@@ -19,10 +19,8 @@
 import {
   getCommentAuthors,
   getMentionedThreads,
-  hasHumanReply,
   isDraftThread,
   isMentionedThread,
-  isRobotThread,
   isUnresolved,
   lastUpdated,
 } from '../../../utils/comment-util';
@@ -142,8 +140,7 @@
    * ATTENTION! this.threads should never be used directly within the component.
    *
    * Either use getAllThreads(), which applies filters that are inherent to what
-   * the component is supposed to render,
-   * e.g. onlyShowRobotCommentsWithHumanReply.
+   * the component is supposed to render.
    *
    * Or use getDisplayedThreads(), which applies the currently selected filters
    * on top.
@@ -158,12 +155,6 @@
   @property({type: Boolean, attribute: 'unresolved-only'})
   unresolvedOnly = false;
 
-  @property({
-    type: Boolean,
-    attribute: 'only-show-robot-comments-with-human-reply',
-  })
-  onlyShowRobotCommentsWithHumanReply = false;
-
   @property({type: Boolean, attribute: 'hide-dropdown'})
   hideDropdown = false;
 
@@ -522,12 +513,7 @@
    */
   // private, but visible for testing
   getAllThreads() {
-    return this.threads.filter(
-      t =>
-        !this.onlyShowRobotCommentsWithHumanReply ||
-        !isRobotThread(t) ||
-        hasHumanReply(t)
-    );
+    return this.threads;
   }
 
   /**
@@ -566,11 +552,6 @@
       if (!hasACommentFromASelectedAuthor) return false;
     }
 
-    // This is probably redundant, because getAllThreads() filters this out.
-    if (this.onlyShowRobotCommentsWithHumanReply) {
-      if (isRobotThread(thread) && !hasHumanReply(thread)) return false;
-    }
-
     if (this.mentionsOnly && !isMentionedThread(thread, this.account))
       return false;
 
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.ts b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.ts
index 3a06f8d..95bfa1d 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.ts
@@ -29,7 +29,6 @@
   Timestamp,
 } from '../../../api/rest-api';
 import {
-  RobotId,
   UrlEncodedCommentId,
   RevisionPatchSetNum,
   CommentThread,
@@ -222,7 +221,6 @@
             updated: '2015-12-08 15:16:15.000000000' as Timestamp,
             message: 'test',
             unresolved: true,
-            robot_id: 'rc1' as RobotId,
           },
         ],
         patchNum: 4 as RevisionPatchSetNum,
@@ -247,7 +245,6 @@
             updated: '2015-12-09 15:16:15.000000000' as Timestamp,
             message: 'test',
             unresolved: true,
-            robot_id: 'rc2' as RobotId,
           },
           {
             path: '/COMMIT_MSG',
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-chip-for-label.ts b/polygerrit-ui/app/elements/checks/gr-checks-chip-for-label.ts
new file mode 100644
index 0000000..5656cfb
--- /dev/null
+++ b/polygerrit-ui/app/elements/checks/gr-checks-chip-for-label.ts
@@ -0,0 +1,97 @@
+/**
+ * @license
+ * Copyright 2025 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+import '../change/gr-change-summary/gr-checks-chip';
+import {LitElement, html, nothing} from 'lit';
+import {customElement, property, state} from 'lit/decorators.js';
+import {Category, RunStatus} from '../../api/checks';
+import {Tab} from '../../constants/constants';
+import {fireShowTab} from '../../utils/event-util';
+import {CheckRun, checksModelToken} from '../../models/checks/checks-model';
+import {resolve} from '../../models/dependency';
+import {subscribe} from '../lit/subscription-controller';
+import {
+  countErrorRunsForLabel,
+  countRunningRunsForLabel,
+} from './gr-checks-util';
+
+@customElement('gr-checks-chip-for-label')
+export class GrChecksChipForLabel extends LitElement {
+  @property({type: Array})
+  labels: string[] = [];
+
+  @property({type: Boolean})
+  showRunning = false;
+
+  @state() runs: CheckRun[] = [];
+
+  private readonly getChecksModel = resolve(this, checksModelToken);
+
+  constructor() {
+    super();
+    subscribe(
+      this,
+      () => this.getChecksModel().allRunsLatestPatchsetLatestAttempt$,
+      x => (this.runs = x)
+    );
+  }
+
+  override render() {
+    const {errorRuns, errorRunsCount} = countErrorRunsForLabel(
+      this.runs,
+      this.labels
+    );
+    if (errorRunsCount > 0) {
+      return this.renderChecksCategoryChip(
+        errorRuns,
+        errorRunsCount,
+        Category.ERROR
+      );
+    }
+    if (!this.showRunning) return nothing;
+    const {runningRuns, runningRunsCount} = countRunningRunsForLabel(
+      this.runs,
+      this.labels
+    );
+    if (runningRunsCount > 0) {
+      return this.renderChecksCategoryChip(
+        runningRuns,
+        runningRunsCount,
+        RunStatus.RUNNING
+      );
+    }
+    return nothing;
+  }
+
+  private renderChecksCategoryChip(
+    runs: CheckRun[],
+    runsCount: number,
+    category: Category | RunStatus
+  ) {
+    if (runsCount === 0) return;
+    const links = [];
+    if (runs.length === 1 && runs[0].statusLink) {
+      links.push(runs[0].statusLink);
+    }
+    return html`<gr-checks-chip
+      .text=${`${runsCount}`}
+      .links=${links}
+      .statusOrCategory=${category}
+      @click=${() => {
+        fireShowTab(this, Tab.CHECKS, false, {
+          checksTab: {
+            statusOrCategory: category,
+          },
+        });
+      }}
+    ></gr-checks-chip>`;
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'gr-checks-chip-for-label': GrChecksChipForLabel;
+  }
+}
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-chip-for-label_test.ts b/polygerrit-ui/app/elements/checks/gr-checks-chip-for-label_test.ts
new file mode 100644
index 0000000..7e35c89
--- /dev/null
+++ b/polygerrit-ui/app/elements/checks/gr-checks-chip-for-label_test.ts
@@ -0,0 +1,61 @@
+/**
+ * @license
+ * Copyright 2025 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {Category} from '../../api/checks';
+import '../../test/common-test-setup';
+import {createCheckResult, createRun} from '../../test/test-data-generators';
+import {queryAndAssert} from '../../utils/common-util';
+import {GrChecksChip} from '../change/gr-change-summary/gr-checks-chip';
+import './gr-checks-chip-for-label';
+import {GrChecksChipForLabel} from './gr-checks-chip-for-label';
+import {fixture, assert} from '@open-wc/testing';
+import {html} from 'lit';
+
+suite('gr-checks-chip-for-label test', () => {
+  let element: GrChecksChipForLabel;
+
+  setup(async () => {
+    element = await fixture<GrChecksChipForLabel>(
+      html`<gr-checks-chip-for-label></gr-checks-chip-for-label>`
+    );
+    element.runs = [
+      createRun({
+        labelName: 'Verified',
+
+        results: [
+          createCheckResult({
+            category: Category.ERROR,
+          }),
+        ],
+      }),
+    ];
+    await element.updateComplete;
+
+    element.labels = ['Verified'];
+    await element.updateComplete;
+  });
+
+  test('renders loading', async () => {
+    assert.shadowDom.equal(
+      element,
+      /* HTML */ '<gr-checks-chip></gr-checks-chip>'
+    );
+
+    const checksChip = queryAndAssert<GrChecksChip>(element, 'gr-checks-chip');
+    assert.shadowDom.equal(
+      checksChip,
+      /* HTML */ `<div
+        aria-label="1 error result"
+        class="checksChip error font-small"
+        role="link"
+        tabindex="0"
+      >
+        <gr-icon filled="" icon="error"> </gr-icon>
+        <div class="text">1</div>
+      </div>`
+    );
+  });
+});
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
index d68cdbf..662c560 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
@@ -212,6 +212,9 @@
   @state()
   shouldRender = false;
 
+  @state()
+  runs: CheckRun[] = [];
+
   private readonly reporting = getAppContext().reportingService;
 
   private getChecksModel = resolve(this, checksModelToken);
@@ -223,6 +226,13 @@
       () => this.getChecksModel().checksSelectedAttemptNumber$,
       x => (this.selectedAttempt = x)
     );
+    subscribe(
+      this,
+      () => this.getChecksModel().allRunsSelectedPatchset$,
+      x => {
+        this.runs = x;
+      }
+    );
   }
 
   override firstUpdated() {
@@ -296,6 +306,18 @@
       attempt !== ALL_ATTEMPTS;
     const selected = this.selectedAttempt === attempt;
     return html`<div class="attemptDetail">
+      ${when(
+        typeof attempt === 'number',
+        () => html` <gr-hovercard-run
+          .run=${this.runs.find(
+            r =>
+              r.attempt === attempt &&
+              r.checkName === this.run?.checkName &&
+              r.pluginName === this.run?.pluginName
+          )}
+          .attempt=${attempt}
+        ></gr-hovercard-run>`
+      )}
       <input
         type="radio"
         id=${id}
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-util.ts b/polygerrit-ui/app/elements/checks/gr-checks-util.ts
index f1a3fb9..0f844ae 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-util.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-util.ts
@@ -3,10 +3,13 @@
  * Copyright 2021 Google LLC
  * SPDX-License-Identifier: Apache-2.0
  */
+import {Category, RunStatus} from '../../api/checks';
 import {CheckRun, RunResult} from '../../models/checks/checks-model';
 import {
   ALL_ATTEMPTS,
   AttemptChoice,
+  getResultsOf,
+  hasResultsOf,
   LATEST_ATTEMPT,
 } from '../../models/checks/checks-util';
 import {fire} from '../../utils/event-util';
@@ -44,3 +47,32 @@
     regExp.test(result.message ?? '')
   );
 }
+
+export function countErrorRunsForLabel(
+  runs: CheckRun[],
+  labels: string[]
+): {errorRuns: CheckRun[]; errorRunsCount: number} {
+  const errorRuns = runs
+    .filter(run => hasResultsOf(run, Category.ERROR))
+    .filter(run => run.labelName && labels.includes(run.labelName));
+  const errorRunsCount = errorRuns.reduce(
+    (sum, run) => sum + getResultsOf(run, Category.ERROR).length,
+    0
+  );
+  return {errorRuns, errorRunsCount};
+}
+
+export function countRunningRunsForLabel(
+  runs: CheckRun[],
+  labels: string[]
+): {runningRuns: CheckRun[]; runningRunsCount: number} {
+  const runningRuns = runs
+    .filter(r => r.isLatestAttempt)
+    .filter(
+      r => r.status === RunStatus.RUNNING || r.status === RunStatus.SCHEDULED
+    )
+    .filter(run => run.labelName && labels.includes(run.labelName));
+
+  const runningRunsCount = runningRuns.length;
+  return {runningRuns, runningRunsCount};
+}
diff --git a/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts b/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
index cc3ce77..b38a30e 100644
--- a/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
+++ b/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
@@ -20,6 +20,7 @@
 import {HovercardMixin} from '../../mixins/hovercard-mixin/hovercard-mixin';
 import {css, html, LitElement} from 'lit';
 import {checksStyles} from './gr-checks-styles';
+import {when} from 'lit/directives/when.js';
 
 // This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
 const base = HovercardMixin(LitElement);
@@ -29,6 +30,9 @@
   @property({type: Object})
   run?: RunResult | CheckRun;
 
+  @property({type: Number})
+  attempt?: number;
+
   static override get styles() {
     return [
       fontStyles,
@@ -146,6 +150,7 @@
           <div class="sectionContent">
             <h3 class="name heading-3">
               <span>${this.run.checkName}</span>
+              ${when(this.attempt, () => html`(Attempt ${this.attempt})`)}
             </h3>
           </div>
         </div>
@@ -196,6 +201,8 @@
   }
 
   private renderAttemptSection() {
+    // If an attempt is specified, we don't need to render the attempt section.
+    if (this.attempt) return;
     if (this.hideAttempts()) return;
     const attempts = this.computeAttempts();
     return html`
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
index 9f87d99..0180495 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
@@ -167,7 +167,8 @@
   // Matches /admin/repos/<repos>,access.
   REPO_DASHBOARDS: /^\/admin\/repos\/(.+),dashboards$/,
 
-  REPO_SUBMIT_REQUIREMENTS: /^\/admin\/repos\/(.+),submit-requirements$/,
+  REPO_SUBMIT_REQUIREMENTS:
+    /^\/admin\/repos\/(.+),submit-requirements\/?(?:\/q\/filter:(.*?))?(?:,(\d+))?$/,
 
   // Matches /admin/plugins with optional filter and offset.
   PLUGIN_LIST: /^\/admin\/plugins\/?(?:\/q\/filter:(.*?))?(?:,(\d+))?$/,
@@ -791,7 +792,8 @@
     this.mapRoute(
       RoutePattern.REPO_SUBMIT_REQUIREMENTS,
       'handleRepoSubmitRequirementsRoute',
-      ctx => this.handleRepoSubmitRequirementsRoute(ctx)
+      ctx => this.handleRepoSubmitRequirementsRoute(ctx),
+      true
     );
 
     this.mapRoute(RoutePattern.BRANCH_LIST, 'handleBranchListRoute', ctx =>
@@ -1229,6 +1231,8 @@
       view: GerritView.REPO,
       detail: RepoDetailView.SUBMIT_REQUIREMENTS,
       repo,
+      filter: ctx.params[1] ?? null,
+      offset: ctx.params[2] ?? '0',
     };
     // Note that router model view must be updated before view models.
     this.setState(state);
@@ -1389,16 +1393,14 @@
     const commentId = ctx.params[2] as UrlEncodedCommentId;
 
     this.restApiService.addRepoNameToCache(changeNum, repo);
-    const [comments, robotComments, drafts, change] = await Promise.all([
+    const [comments, drafts, change] = await Promise.all([
       this.restApiService.getDiffComments(changeNum),
-      this.restApiService.getDiffRobotComments(changeNum),
       this.restApiService.getDiffDrafts(changeNum),
       this.restApiService.getChangeDetail(changeNum),
     ]);
 
     const comment =
       findComment(addPath(comments), commentId) ??
-      findComment(addPath(robotComments), commentId) ??
       findComment(addPath(drafts), commentId);
     const path = comment?.path;
     const patchsets = computeAllPatchSets(change);
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.ts b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.ts
index d33fa1d..09831af 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.ts
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.ts
@@ -162,6 +162,7 @@
       'handlePluginListRoute',
       'handleRepoCommandsRoute',
       'handleRepoEditFileRoute',
+      'handleRepoSubmitRequirementsRoute',
       'handleServerInfoRoute',
       'handleSettingsLegacyRoute',
       'handleSettingsRoute',
@@ -191,7 +192,6 @@
       'handleRepoGeneralRoute',
       'handleRepoListRoute',
       'handleRepoRoute',
-      'handleRepoSubmitRequirementsRoute',
       'handleQueryLegacySuffixRoute',
       'handleQueryRoute',
       'handleRegisterRoute',
@@ -734,6 +734,8 @@
           ...createRepoViewState(),
           detail: RepoDetailView.SUBMIT_REQUIREMENTS,
           repo: '4321' as RepoName,
+          filter: '',
+          offset: '',
         });
       });
 
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
index 34200a4..f746d13 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
@@ -354,14 +354,6 @@
           this.patchNum,
           fixSuggestion.replacements
         );
-      } else {
-        // TODO(b/227463363) Remove once Robot Comments are deprecated.
-        // We don't use this for user suggestions or comments.fix_suggestions.
-        res = await this.restApiService.getRobotCommentFixPreview(
-          this.changeNum,
-          this.patchNum,
-          fixSuggestion.fix_id
-        );
       }
       if (res) {
         this.currentPreviews = Object.keys(res).map(key => {
@@ -488,23 +480,6 @@
           errorText,
         });
       }
-      // Robot Comments are deprecated
-    } else {
-      res = await this.restApiService.applyRobotFixSuggestion(
-        changeNum,
-        patchNum,
-        this.currentFix.fix_id
-      );
-      this.reporting.timeEnd(Timing.APPLY_FIX_LOAD, {
-        method: 'apply-fix-dialog',
-        description: this.fixSuggestions?.[0].description,
-        isRobotComment: true,
-        fileExtension: getFileExtension(
-          this.fixSuggestions?.[0].replacements?.[0].path ?? ''
-        ),
-        success: res.ok,
-        status: res.status,
-      });
     }
     if (res?.ok) {
       this.getNavigation().setUrl(
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
index 955305e..39066f3 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
@@ -21,7 +21,6 @@
   getCurrentRevision,
 } from '../../../test/test-data-generators';
 import {createDefaultDiffPrefs} from '../../../constants/constants';
-import {DiffInfo} from '../../../types/diff';
 import {OpenFixPreviewEventDetail} from '../../../types/events';
 import {GrButton} from '../../shared/gr-button/gr-button';
 import {fixture, html, assert} from '@open-wc/testing';
@@ -90,71 +89,13 @@
 
   suite('dialog open', () => {
     setup(() => {
-      const diffInfo1: DiffInfo = {
-        meta_a: {
-          name: 'f1',
-          content_type: 'text',
-          lines: 10,
-        },
-        meta_b: {
-          name: 'f1',
-          content_type: 'text',
-          lines: 12,
-        },
-        content: [
-          {
-            ab: ['loqlwkqll'],
-          },
-          {
-            b: ['qwqqsqw'],
-          },
-          {
-            ab: ['qwqqsqw', 'qweqeqweqeq', 'qweqweq'],
-          },
-        ],
-        change_type: 'MODIFIED',
-        intraline_status: 'OK',
-      };
-
-      const diffInfo2: DiffInfo = {
-        meta_a: {
-          name: 'f2',
-          content_type: 'text',
-          lines: 10,
-        },
-        meta_b: {
-          name: 'f2',
-          content_type: 'text',
-          lines: 12,
-        },
-        content: [
-          {
-            ab: ['eqweqweqwex'],
-          },
-          {
-            b: ['zassdasd'],
-          },
-          {
-            ab: ['zassdasd', 'dasdasda', 'asdasdad'],
-          },
-        ],
-        change_type: 'MODIFIED',
-        intraline_status: 'OK',
-      };
-
-      stubRestApi('getRobotCommentFixPreview').returns(
-        Promise.resolve({
-          f1: diffInfo1,
-          f2: diffInfo2,
-        })
-      );
       sinon.stub(element.applyFixModal!, 'showModal');
     });
 
     test('dialog opens fetch and sets previews', async () => {
       await open(TWO_FIXES);
       assert.equal(element.currentFix!.fix_id, 'fix_1');
-      assert.equal(element.currentPreviews.length, 2);
+      assert.equal(element.currentPreviews.length, 0);
       const button = getConfirmButton();
       assert.isFalse(button.hasAttribute('disabled'));
       assert.equal(button.getAttribute('title'), '');
@@ -175,7 +116,7 @@
       element,
       /* HTML */ `
         <dialog id="applyFixModal" tabindex="-1" open="">
-          <gr-dialog id="applyFixDialog" role="dialog" loading="">
+          <gr-dialog id="applyFixDialog" role="dialog">
             <div slot="header">Fix fix_1</div>
             <div slot="main"></div>
             <div class="fix-picker" slot="footer">
@@ -206,8 +147,6 @@
   });
 
   test('next button state updated when suggestions changed', async () => {
-    stubRestApi('getRobotCommentFixPreview').returns(Promise.resolve({}));
-
     await open(ONE_FIX);
     await element.updateComplete;
     assert.notOk(element.nextFix);
@@ -218,63 +157,6 @@
     assert.notOk(element.nextFix.disabled);
   });
 
-  test('preview endpoint throws error should reset dialog', async () => {
-    stubRestApi('getRobotCommentFixPreview').returns(
-      Promise.reject(new Error('backend error'))
-    );
-    try {
-      await open(TWO_FIXES);
-    } catch (error) {
-      // expected
-    }
-    assert.equal(element.currentFix, undefined);
-  });
-
-  test('apply fix button should call apply, navigate to change view and fire close', async () => {
-    const applyRobotFixSuggestionStub = stubRestApi(
-      'applyRobotFixSuggestion'
-    ).returns(Promise.resolve(new Response(null, {status: 200})));
-    element.currentFix = createFixSuggestionInfo('123');
-    element.hasEdit = true;
-
-    const closeFixPreviewEventSpy = sinon.spy();
-    element.onCloseFixPreviewCallbacks.push(closeFixPreviewEventSpy);
-
-    await element.handleApplyFix(new CustomEvent('confirm'));
-
-    sinon.assert.calledOnceWithExactly(
-      applyRobotFixSuggestionStub,
-      element.change!._number,
-      2 as PatchSetNum,
-      '123'
-    );
-    assert.isTrue(setUrlStub.called);
-    assert.equal(setUrlStub.lastCall.firstArg, '/c/test-project/+/42/2..edit');
-
-    sinon.assert.calledOnceWithExactly(closeFixPreviewEventSpy, true);
-    // reset gr-apply-fix-dialog and close
-    assert.equal(element.currentFix, undefined);
-    assert.equal(element.currentPreviews.length, 0);
-  });
-
-  test('should not navigate to change view if incorect reponse', async () => {
-    const applyRobotFixSuggestionStub = stubRestApi(
-      'applyRobotFixSuggestion'
-    ).returns(Promise.resolve(new Response(null, {status: 500})));
-    element.currentFix = createFixSuggestionInfo('fix_123');
-
-    await element.handleApplyFix(new CustomEvent('confirm'));
-
-    sinon.assert.calledWithExactly(
-      applyRobotFixSuggestionStub,
-      element.change!._number,
-      2 as PatchSetNum,
-      'fix_123'
-    );
-    assert.isFalse(setUrlStub.called);
-    assert.equal(element.isApplyFixLoading, false);
-  });
-
   test('select fix forward and back of multiple suggested fixes', async () => {
     sinon.stub(element.applyFixModal!, 'showModal');
 
@@ -285,24 +167,6 @@
     assert.equal(element.currentFix!.fix_id, 'fix_1');
   });
 
-  test('server-error should throw for failed apply call', async () => {
-    stubRestApi('applyRobotFixSuggestion').returns(
-      Promise.reject(new Error('backend error'))
-    );
-    element.currentFix = createFixSuggestionInfo('fix_123');
-
-    const closeFixPreviewEventSpy = sinon.spy();
-    element.onCloseFixPreviewCallbacks.push(closeFixPreviewEventSpy);
-
-    let expectedError;
-    await element.handleApplyFix(new CustomEvent('click')).catch(e => {
-      expectedError = e;
-    });
-    assert.isOk(expectedError);
-    assert.isFalse(setUrlStub.called);
-    sinon.assert.notCalled(closeFixPreviewEventSpy);
-  });
-
   test('onCancel fires close with correct parameters', () => {
     const closeFixPreviewEventSpy = sinon.spy();
     element.onCloseFixPreviewCallbacks.push(closeFixPreviewEventSpy);
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
index aedeb6d..56a4b64 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
@@ -6,7 +6,6 @@
 import {
   PatchRange,
   PatchSetNum,
-  RobotCommentInfo,
   FileInfo,
   PARENT,
   CommentThread,
@@ -33,8 +32,6 @@
 export class ChangeComments {
   private readonly _comments: {[path: string]: CommentInfo[]};
 
-  private readonly _robotComments: {[path: string]: RobotCommentInfo[]};
-
   private readonly _drafts: {[path: string]: DraftInfo[]};
 
   private readonly _portedComments: {[path: string]: CommentInfo[]};
@@ -43,13 +40,11 @@
 
   constructor(
     comments?: {[path: string]: CommentInfo[]},
-    robotComments?: {[path: string]: RobotCommentInfo[]},
     drafts?: {[path: string]: DraftInfo[]},
     portedComments?: {[path: string]: CommentInfo[]},
     portedDrafts?: {[path: string]: DraftInfo[]}
   ) {
     this._comments = addPath(comments);
-    this._robotComments = addPath(robotComments);
     this._drafts = addPath(drafts);
     this._portedComments = portedComments || {};
     this._portedDrafts = portedDrafts || {};
@@ -61,8 +56,7 @@
 
   /**
    * Get an object mapping file paths to a boolean representing whether that
-   * path contains diff comments in the given patch set (including drafts and
-   * robot comments).
+   * path contains diff comments in the given patch set (including drafts).
    *
    * Paths with comments are mapped to true, whereas paths without comments
    * are not mapped.
@@ -74,7 +68,6 @@
     const responses: {[path: string]: Comment[]}[] = [
       this._comments,
       this.drafts,
-      this._robotComments,
     ];
     const commentMap: CommentMap = {};
     for (const response of responses) {
@@ -91,14 +84,14 @@
   }
 
   /**
-   * Gets all the comments and robot comments for the given change.
+   * Gets all the comments for the given change.
    */
   getAllPublishedComments(patchNum?: PatchSetNum) {
     return this.getAllComments(false, patchNum);
   }
 
   /**
-   * Gets all the comments and robot comments for the given change.
+   * Gets all the comments for the given change.
    */
   getAllComments(includeDrafts?: boolean, patchNum?: PatchSetNum) {
     const paths = this.getPaths();
@@ -126,7 +119,7 @@
   }
 
   /**
-   * Get the comments (robot comments) for a path and optional patch num.
+   * Get the comments for a path and optional patch num.
    *
    * This method will always return a new shallow copy of all comments,
    * so manipulation on one copy won't affect other copies.
@@ -137,9 +130,7 @@
     patchNum?: PatchSetNum,
     includeDrafts?: boolean
   ): Comment[] {
-    const comments: Comment[] = this._comments[path] || [];
-    const robotComments = this._robotComments[path] || [];
-    let allComments = comments.concat(robotComments);
+    let allComments: Comment[] = this._comments[path] || [];
     if (includeDrafts) {
       const drafts = this.getAllDraftsForPath(path);
       allComments = allComments.concat(drafts);
@@ -153,7 +144,7 @@
   }
 
   /**
-   * Get the comments (robot comments) for a file.
+   * Get the comments for a file.
    *
    * // TODO(taoalpha): maybe merge in *ForPath
    */
@@ -203,7 +194,7 @@
   }
 
   /**
-   * Get the comments (with drafts and robot comments) for a path and
+   * Get the comments (with drafts) for a path and
    * patch-range. Returns an array containing comments from either side of the
    * patch range for that path.
    *
@@ -213,18 +204,14 @@
   getCommentsForPath(path: string, patchRange: PatchRange): Comment[] {
     let comments: Comment[] = [];
     let drafts: DraftInfo[] = [];
-    let robotComments: RobotCommentInfo[] = [];
     if (this._comments && this._comments[path]) {
       comments = this._comments[path];
     }
     if (this.drafts && this.drafts[path]) {
       drafts = this.drafts[path];
     }
-    if (this._robotComments && this._robotComments[path]) {
-      robotComments = this._robotComments[path];
-    }
 
-    const all = comments.concat(drafts).concat(robotComments);
+    const all = comments.concat(drafts);
     const final = all
       .filter(c => isInPatchRange(c, patchRange))
       .map(c => {
@@ -284,10 +271,7 @@
     const allComments: Comment[] = this.getAllCommentsForFile(file, true);
 
     return createCommentThreads(allComments).filter(thread => {
-      // Robot comments and drafts are not ported over. A human reply to
-      // the robot comment will be ported over, therefore it's possible to
-      // have the root comment of the thread not be ported, hence loop over
-      // entire thread
+      // Drafts are not ported over.
       const portedComment = portedComments.find(portedComment =>
         thread.comments.some(c => id(portedComment) === id(c))
       );
@@ -338,7 +322,7 @@
   }
 
   /**
-   * Get the comments (with drafts and robot comments) for a file and
+   * Get the comments (with drafts) for a file and
    * patch-range. Returns an object with left and right properties mapping to
    * arrays of comments in on either side of the patch range for that path.
    *
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.ts b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.ts
index 0a0c922..3bf2ac35 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.ts
@@ -18,7 +18,6 @@
   createChangeComments,
   createCommentThread,
   createFileInfo,
-  createRobotComment,
 } from '../../../test/test-data-generators';
 import {CommentSide, FileInfoStatus} from '../../../constants/constants';
 import {
@@ -30,7 +29,6 @@
   PatchRange,
   PatchSetNum,
   RevisionPatchSetNum,
-  RobotCommentInfo,
   Timestamp,
   UrlEncodedCommentId,
 } from '../../../types/common';
@@ -43,7 +41,6 @@
   suite('_changeComment methods', () => {
     setup(() => {
       stubRestApi('getDiffComments').resolves({});
-      stubRestApi('getDiffRobotComments').resolves({});
       stubRestApi('getDiffDrafts').resolves({});
     });
 
@@ -124,7 +121,6 @@
               comment1,
             ],
           },
-          {} /* robot comments */,
           {} /* drafts */,
           portedComments,
           {} /* ported drafts */
@@ -202,7 +198,6 @@
             // comment that is not ported over
             'karma.conf.js': [comment2],
           },
-          {} /* robot comments */,
           {
             /* drafts */ 'karma.conf.js': [draft2],
           },
@@ -234,7 +229,6 @@
             // comment left on Base
             'karma.conf.js': [comment3],
           },
-          {} /* robot comments */,
           {
             /* drafts */ 'karma.conf.js': [draft2],
           },
@@ -288,7 +282,6 @@
             // comment left on Base
             'karma.conf.js': [comment4],
           },
-          {} /* robot comments */,
           {
             /* drafts */ 'karma.conf.js': [draft2],
           },
@@ -359,7 +352,6 @@
       test('drafts are ported over', () => {
         changeComments = new ChangeComments(
           {} /* comments */,
-          {} /* robotComments */,
           {
             /* drafts */
             // draft1: resolved draft that will be ported over to ps 4
@@ -460,29 +452,14 @@
     suite('comment ranges and paths', () => {
       const comments = [
         {
-          ...createRobotComment(),
+          // legacy from when we were still supporting robot comments
+          ...createComment(),
           id: '01' as UrlEncodedCommentId,
-          patch_set: 2 as RevisionPatchSetNum,
-          path: 'file/1',
-          side: CommentSide.PARENT,
-          line: 1,
-          updated: makeTime(1),
-          range: {
-            start_line: 1,
-            start_character: 2,
-            end_line: 2,
-            end_character: 2,
-          },
         },
         {
-          ...createRobotComment(),
+          // legacy from when we were still supporting robot comments
+          ...createComment(),
           id: '02' as UrlEncodedCommentId,
-          in_reply_to: '04' as UrlEncodedCommentId,
-          patch_set: 2 as RevisionPatchSetNum,
-          path: 'file/1',
-          unresolved: true,
-          line: 1,
-          updated: makeTime(3),
         },
         {
           ...createComment(),
@@ -589,9 +566,6 @@
         'file/1': [comments[11], comments[12]],
         'file/2': [comments[13]],
       };
-      const robotComments: {[path: string]: RobotCommentInfo[]} = {
-        'file/1': [comments[0], comments[1]],
-      };
       const commentsByFile: {[path: string]: CommentInfo[]} = {
         'file/1': [comments[2], comments[3]],
         'file/2': [comments[4], comments[5]],
@@ -606,7 +580,6 @@
       setup(() => {
         changeComments = new ChangeComments(
           commentsByFile,
-          robotComments,
           drafts,
           {} /* portedComments */,
           {} /* portedDrafts */
@@ -697,7 +670,7 @@
       test('getAllCommentsForPath', () => {
         let path = 'file/1';
         let comments = changeComments.getAllCommentsForPath(path);
-        assert.equal(comments.length, 4);
+        assert.equal(comments.length, 2);
         path = 'file/2';
         comments = changeComments.getAllCommentsForPath(path, 2 as PatchSetNum);
         assert.equal(comments.length, 1);
@@ -916,7 +889,7 @@
             patchNum: 2 as PatchSetNum,
             path: 'file/1',
           }).length,
-          3
+          2
         );
         assert.deepEqual(
           changeComments.computeCommentThreads({
@@ -979,32 +952,32 @@
       test('getAllPublishedComments', () => {
         let publishedComments = changeComments.getAllPublishedComments();
         assert.equal(Object.keys(publishedComments).length, 4);
-        assert.equal(Object.keys(publishedComments['file/1']).length, 4);
+        assert.equal(Object.keys(publishedComments['file/1']).length, 2);
         assert.equal(Object.keys(publishedComments['file/2']).length, 2);
         publishedComments = changeComments.getAllPublishedComments(
           2 as PatchSetNum
         );
-        assert.equal(Object.keys(publishedComments['file/1']).length, 4);
+        assert.equal(Object.keys(publishedComments['file/1']).length, 2);
         assert.equal(Object.keys(publishedComments['file/2']).length, 1);
       });
 
       test('getAllComments', () => {
         let comments = changeComments.getAllComments();
         assert.equal(Object.keys(comments).length, 4);
-        assert.equal(Object.keys(comments['file/1']).length, 4);
+        assert.equal(Object.keys(comments['file/1']).length, 2);
         assert.equal(Object.keys(comments['file/2']).length, 2);
         comments = changeComments.getAllComments(false, 2 as PatchSetNum);
         assert.equal(Object.keys(comments).length, 4);
-        assert.equal(Object.keys(comments['file/1']).length, 4);
+        assert.equal(Object.keys(comments['file/1']).length, 2);
         assert.equal(Object.keys(comments['file/2']).length, 1);
         // Include drafts
         comments = changeComments.getAllComments(true);
         assert.equal(Object.keys(comments).length, 4);
-        assert.equal(Object.keys(comments['file/1']).length, 6);
+        assert.equal(Object.keys(comments['file/1']).length, 4);
         assert.equal(Object.keys(comments['file/2']).length, 3);
         comments = changeComments.getAllComments(true, 2 as PatchSetNum);
         assert.equal(Object.keys(comments).length, 4);
-        assert.equal(Object.keys(comments['file/1']).length, 6);
+        assert.equal(Object.keys(comments['file/1']).length, 4);
         assert.equal(Object.keys(comments['file/2']).length, 1);
       });
 
@@ -1013,7 +986,6 @@
           {
             ...createCommentThread([
               {...comments[3], path: 'file/1'},
-              {...comments[1], path: 'file/1'},
               {...comments[12], path: 'file/1'},
             ]),
           },
@@ -1021,9 +993,6 @@
             ...createCommentThread([{...comments[11], path: 'file/1'}]),
           },
           {
-            ...createCommentThread([{...comments[0], path: 'file/1'}]),
-          },
-          {
             ...createCommentThread([{...comments[2], path: 'file/1'}]),
           },
           {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index 1cba745..07cea33 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -107,6 +107,7 @@
 import {formStyles} from '../../../styles/form-styles';
 import {NormalizedFileInfo} from '../../change/gr-file-list/gr-file-list';
 import {configModelToken} from '../../../models/config/config-model';
+import {trimWithEllipsis} from '../../../utils/string-util';
 
 const LOADING_BLAME = 'Loading blame information. This may take a while ...';
 const LOADED_BLAME = 'Blame loaded';
@@ -889,7 +890,9 @@
         <a href=${ifDefined(this.getChangeModel().changeUrl())}
           >${this.changeNum}</a
         ><span class="changeNumberColon">:</span>
-        <span class="headerSubject">${this.change?.subject}</span>
+        <span class="headerSubject"
+          >${trimWithEllipsis(this.change?.subject, 80)}</span
+        >
         <input
           id="reviewed"
           class="reviewed hideOnEdit"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts
index 1899778..a805e9c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.ts
@@ -134,7 +134,6 @@
       stubRestApi('saveFileReviewed').returns(Promise.resolve(new Response()));
       diffCommentsStub = stubRestApi('getDiffComments');
       diffCommentsStub.returns(Promise.resolve({}));
-      stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
       stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
       stubRestApi('getPortedComments').returns(Promise.resolve({}));
 
@@ -167,7 +166,6 @@
 
       commentsModel.setState({
         comments: {},
-        robotComments: {},
         drafts: {},
         portedComments: {},
         portedDrafts: {},
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
index 5c7ab03..0997d69 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
@@ -47,7 +47,11 @@
 import {commentsModelToken} from '../../../models/comments/comments-model';
 import {resolve} from '../../../models/dependency';
 import {ValueChangedEvent} from '../../../types/events';
-import {changeModelToken} from '../../../models/change/change-model';
+import {
+  changeModelToken,
+  RevisionFileUpdateStatus,
+  RevisionUpdatedFiles,
+} from '../../../models/change/change-model';
 import {changeViewModelToken} from '../../../models/views/change';
 import {fireNoBubbleNoCompose} from '../../../utils/event-util';
 import {FlagsService, KnownExperimentId} from '../../../services/flags/flags';
@@ -119,6 +123,9 @@
   @state()
   changeComments?: ChangeComments;
 
+  @state()
+  revisionUpdatedFiles?: RevisionUpdatedFiles;
+
   private readonly reporting: ReportingService =
     getAppContext().reportingService;
 
@@ -167,6 +174,11 @@
       () => this.getCommentsModel().changeComments$,
       x => (this.changeComments = x)
     );
+    subscribe(
+      this,
+      () => this.getChangeModel().revisionUpdatedFiles$,
+      x => (this.revisionUpdatedFiles = x)
+    );
   }
 
   static override get styles() {
@@ -268,7 +280,7 @@
       const entry: DropdownItem = this.createDropdownEntry(
         basePatchNum,
         'Patchset ',
-        shorten(basePatch.sha)!
+        basePatch.sha
       );
       dropdownContent.push({
         ...entry,
@@ -325,7 +337,7 @@
       const entry = this.createDropdownEntry(
         patchNum,
         patchNum === EDIT ? '' : 'Patchset ',
-        shorten(patch.sha)!
+        patch.sha
       );
       dropdownContent.push({
         ...entry,
@@ -343,7 +355,7 @@
   createDropdownEntry(patchNum: PatchSetNum, prefix: string, sha: string) {
     const entry: DropdownItem = {
       triggerText: `${prefix}${patchNum}`,
-      text: this.computeText(patchNum, prefix, sha),
+      text: this.computeText(patchNum, prefix, shorten(sha)!),
       mobileText: this.computeMobileText(patchNum),
       bottomText: `${this.computePatchSetDescription(patchNum)}`,
       value: patchNum,
@@ -355,6 +367,7 @@
         // don't ignore patchset level comments if the path is not set
         !!this.path /* ignorePatchsetLevelComments*/
       ),
+      deemphasizeReason: this.computeDeemphasizeReason(sha),
     };
     const date = this.computePatchSetDate(patchNum);
     if (date) {
@@ -363,6 +376,17 @@
     return entry;
   }
 
+  private computeDeemphasizeReason(sha: string) {
+    if (!this.path || !this.revisionUpdatedFiles) {
+      return undefined;
+    }
+
+    return this.revisionUpdatedFiles[sha]?.[this.path] ===
+      RevisionFileUpdateStatus.SAME
+      ? 'unmodified'
+      : undefined;
+  }
+
   /**
    * The basePatchNum should always be <= patchNum -- because sortedRevisions
    * is sorted in reverse order (higher patchset nums first), invalid base
@@ -467,6 +491,7 @@
     addFrontSpace?: boolean
   ) {
     const rev = getRevisionByPatchNum(this.sortedRevisions, patchNum);
+
     return rev?.description
       ? (addFrontSpace ? ' ' : '') +
           rev.description.substring(0, PATCH_DESC_MAX_LENGTH)
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.ts b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.ts
index 1400882..2dd4443 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.ts
@@ -42,7 +42,10 @@
 import {fixture, html, assert} from '@open-wc/testing';
 import {testResolver} from '../../../test/common-test-setup';
 import {changeViewModelToken} from '../../../models/views/change';
-import {changeModelToken} from '../../../models/change/change-model';
+import {
+  changeModelToken,
+  RevisionFileUpdateStatus,
+} from '../../../models/change/change-model';
 
 type RevIdToRevisionInfo = {
   [revisionId: string]: RevisionInfo | EditRevisionInfo;
@@ -149,6 +152,7 @@
         bottomText: '',
         value: EDIT,
         commentThreads: [],
+        deemphasizeReason: undefined,
       },
       {
         disabled: true,
@@ -159,6 +163,7 @@
         value: 3,
         date: '2020-02-01 01:02:03.000000000' as Timestamp,
         commentThreads: [],
+        deemphasizeReason: undefined,
       } as DropdownItem,
       {
         disabled: true,
@@ -169,6 +174,7 @@
         value: 2,
         date: '2020-02-01 01:02:03.000000000' as Timestamp,
         commentThreads: [],
+        deemphasizeReason: undefined,
       } as DropdownItem,
       {
         disabled: true,
@@ -179,6 +185,7 @@
         value: 1,
         date: '2020-02-01 01:02:03.000000000' as Timestamp,
         commentThreads: [],
+        deemphasizeReason: undefined,
       } as DropdownItem,
       {
         text: 'Base | ',
@@ -295,6 +302,7 @@
         bottomText: '',
         value: EDIT,
         commentThreads: [],
+        deemphasizeReason: undefined,
       },
       {
         disabled: false,
@@ -305,6 +313,7 @@
         value: 3,
         date: '2020-02-01 01:02:03.000000000' as Timestamp,
         commentThreads: [],
+        deemphasizeReason: undefined,
       } as DropdownItem,
       {
         disabled: false,
@@ -315,6 +324,7 @@
         value: 2,
         date: '2020-02-01 01:02:03.000000000' as Timestamp,
         commentThreads: [],
+        deemphasizeReason: undefined,
       } as DropdownItem,
       {
         disabled: true,
@@ -325,6 +335,7 @@
         value: 1,
         date: '2020-02-01 01:02:03.000000000' as Timestamp,
         commentThreads: [],
+        deemphasizeReason: undefined,
       } as DropdownItem,
     ];
 
@@ -530,4 +541,66 @@
       'Should ignore patchset level comments when path is defined'
     );
   });
+
+  test('revisions without modification are deemphasized', async () => {
+    element.availablePatches = [
+      {num: 3, sha: 'sha3'} as PatchSet,
+      {num: 2, sha: 'sha2'} as PatchSet,
+      {num: 1, sha: 'sha1'} as PatchSet,
+    ];
+    element.sortedRevisions = [
+      createRevision(3),
+      createRevision(2),
+      createRevision(1),
+    ];
+    element.revisionUpdatedFiles = {
+      sha1: {
+        foo: RevisionFileUpdateStatus.MODIFIED,
+        bar: RevisionFileUpdateStatus.MODIFIED,
+      },
+      sha2: {
+        foo: RevisionFileUpdateStatus.SAME,
+        bar: RevisionFileUpdateStatus.MODIFIED,
+      },
+      sha3: {
+        foo: RevisionFileUpdateStatus.UNKNOWN,
+        bar: RevisionFileUpdateStatus.SAME,
+      },
+    };
+    element.path = 'foo';
+    element.revisionInfo = getInfo(element.sortedRevisions);
+    element.patchNum = 3 as PatchSetNumber;
+    element.basePatchNum = PARENT;
+    await element.updateComplete;
+
+    const expectedResult: {triggerText: string; deemphasizeReason?: string}[] =
+      [
+        {
+          triggerText: 'Patchset 3',
+          deemphasizeReason: undefined,
+        },
+        {
+          triggerText: 'Patchset 2',
+          deemphasizeReason: 'unmodified',
+        },
+        {
+          triggerText: 'Patchset 1',
+          deemphasizeReason: undefined,
+        },
+        {
+          triggerText: 'Base',
+          deemphasizeReason: undefined,
+        },
+      ];
+    assert.deepEqual(
+      element.computeBaseDropdownContent().map(
+        x =>
+          ({
+            triggerText: x.triggerText,
+            deemphasizeReason: x.deemphasizeReason,
+          } as {triggerText: string; deemphasizeReason?: string})
+      ),
+      expectedResult
+    );
+  });
 });
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts
index 0e9985d..00c0863 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts
@@ -468,7 +468,7 @@
 
     test('restore hidden by default', () => {
       assert.isTrue(
-        queryAndAssert(element, '#restore').classList.contains('invisible')!
+        queryAndAssert(element, '#restore').classList.contains('invisible')
       );
     });
 
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
index 7f35f04..0033411 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
@@ -265,7 +265,7 @@
               ?disabled=${this.computeSaveDisabled()}
               primary=""
               link=""
-              title="Save and Close the file"
+              title=${this.computeButtonTitle('Save')}
               @click=${this.handleSaveTap}
               >Save</gr-button
             >
@@ -273,7 +273,7 @@
               id="publish"
               link=""
               primary=""
-              title="Publish your edit. A new patchset will be created."
+              title=${this.computeButtonTitle('Publish')}
               @click=${this.handlePublishTap}
               ?disabled=${this.computeSaveDisabled()}
               >Save & Publish</gr-button
@@ -478,6 +478,28 @@
     return this.content === this.newContent;
   }
 
+  private computeButtonTitle(buttonType: 'Save' | 'Publish'): string {
+    const disabledReasonPrefix = `${buttonType} disabled:`;
+
+    if (this.saving) {
+      return `${disabledReasonPrefix} Saving in progress...`;
+    }
+
+    if (this.content === undefined || this.newContent === undefined) {
+      return `${disabledReasonPrefix} Editor is initializing`;
+    }
+    if (this.content === this.newContent) {
+      return `${disabledReasonPrefix} ${
+        buttonType === 'Save' ? 'No changes made' : 'No changes to publish'
+      }`;
+    }
+
+    if (buttonType === 'Save') {
+      return 'Save and Close the file';
+    }
+    return 'Publish your edit. A new patchset will be created.';
+  }
+
   // private but used in test
   handleCloseTap = () => {
     // TODO(kaspern): Add a confirm dialog if there are unsaved changes.
@@ -510,7 +532,7 @@
           HttpMethod.POST,
           '/edit:publish',
           undefined,
-          {notify: NotifyType.NONE},
+          {notify: NotifyType.OWNER_REVIEWERS},
           handleError
         )
         .then(res => {
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.ts
index 3bfeecb..1b17b11 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.ts
@@ -106,7 +106,7 @@
                 primary=""
                 role="button"
                 tabindex="-1"
-                title="Save and Close the file"
+                title="Save disabled: Editor is initializing"
               >
                 Save
               </gr-button>
@@ -118,7 +118,7 @@
                 primary=""
                 role="button"
                 tabindex="-1"
-                title="Publish your edit. A new patchset will be created."
+                title="Publish disabled: Editor is initializing"
               >
                 Save & Publish
               </gr-button>
@@ -600,4 +600,33 @@
       assert.equal(element.storageKey, 'c1_ps1_test');
     });
   });
+
+  suite('save enabled/disabled', () => {
+    test('should be disabled when content is not modified', async () => {
+      element.content = 'initial content';
+      element.newContent = 'initial content';
+      element.saving = false;
+      await element.updateComplete;
+      const saveButton = query<GrButton>(element, '#save');
+      const publishButton = query<GrButton>(element, '#publish');
+      assert.isTrue(saveButton!.disabled, 'save button should be disabled');
+      assert.isTrue(
+        publishButton!.disabled,
+        'publish button should be disabled'
+      );
+    });
+    test('should be enabled when content is modified', async () => {
+      element.content = 'initial content';
+      element.newContent = 'modified content';
+      element.saving = false;
+      await element.updateComplete;
+      const saveButton = query<GrButton>(element, '#save');
+      const publishButton = query<GrButton>(element, '#publish');
+      assert.isFalse(saveButton!.disabled, 'save button should be enabled');
+      assert.isFalse(
+        publishButton!.disabled,
+        'publish button should be enabled'
+      );
+    });
+  });
 });
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.ts b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.ts
index e96fa39..f3c0976 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.ts
@@ -123,7 +123,7 @@
 
     assert.equal(rows.length, 2);
 
-    const nameCells = rows.map(row => queryAll(row, 'td')[1]!.textContent);
+    const nameCells = rows.map(row => queryAll(row, 'td')[1].textContent);
 
     assert.equal(nameCells[0]!, 'gerrit@example.com');
     assert.equal(nameCells[1]!, 'gerrit2@example.com');
diff --git a/polygerrit-ui/app/elements/settings/gr-preferences/gr-preferences_test.ts b/polygerrit-ui/app/elements/settings/gr-preferences/gr-preferences_test.ts
index 26964a0..09b7c1b 100644
--- a/polygerrit-ui/app/elements/settings/gr-preferences/gr-preferences_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-preferences/gr-preferences_test.ts
@@ -297,7 +297,7 @@
     assert.equal(
       Number(
         (
-          valueOf('Changes per page', 'preferences')!
+          valueOf('Changes per page', 'preferences')
             .firstElementChild as GrSelect
         ).bindValue
       ),
@@ -308,51 +308,49 @@
       preferences.theme
     );
     assert.equal(
-      (
-        valueOf('Date/time format', 'preferences')!
-          .firstElementChild as GrSelect
-      ).bindValue,
+      (valueOf('Date/time format', 'preferences').firstElementChild as GrSelect)
+        .bindValue,
       preferences.date_format
     );
     assert.equal(
-      (valueOf('Date/time format', 'preferences')!.lastElementChild as GrSelect)
+      (valueOf('Date/time format', 'preferences').lastElementChild as GrSelect)
         .bindValue,
       preferences.time_format
     );
     assert.equal(
       (
-        valueOf('Email notifications', 'preferences')!
+        valueOf('Email notifications', 'preferences')
           .firstElementChild as GrSelect
       ).bindValue,
       preferences.email_strategy
     );
     assert.equal(
-      (valueOf('Email format', 'preferences')!.firstElementChild as GrSelect)
+      (valueOf('Email format', 'preferences').firstElementChild as GrSelect)
         .bindValue,
       preferences.email_format
     );
     assert.equal(
       (
-        valueOf('Show Relative Dates In Changes Table', 'preferences')!
+        valueOf('Show Relative Dates In Changes Table', 'preferences')
           .firstElementChild as HTMLInputElement
       ).checked,
       false
     );
     assert.equal(
-      (valueOf('Diff view', 'preferences')!.firstElementChild as GrSelect)
+      (valueOf('Diff view', 'preferences').firstElementChild as GrSelect)
         .bindValue,
       preferences.diff_view
     );
     assert.equal(
       (
-        valueOf('Show size bars in file list', 'preferences')!
+        valueOf('Show size bars in file list', 'preferences')
           .firstElementChild as HTMLInputElement
       ).checked,
       true
     );
     assert.equal(
       (
-        valueOf('Publish comments on push', 'preferences')!
+        valueOf('Publish comments on push', 'preferences')
           .firstElementChild as HTMLInputElement
       ).checked,
       false
@@ -362,13 +360,13 @@
         valueOf(
           'Set new changes to "work in progress" by default',
           'preferences'
-        )!.firstElementChild as HTMLInputElement
+        ).firstElementChild as HTMLInputElement
       ).checked,
       false
     );
     assert.equal(
       (
-        valueOf('Disable token highlighting on hover', 'preferences')!
+        valueOf('Disable token highlighting on hover', 'preferences')
           .firstElementChild as HTMLInputElement
       ).checked,
       false
@@ -378,7 +376,7 @@
         valueOf(
           'Insert Signed-off-by Footer For Inline Edit Changes',
           'preferences'
-        )!.firstElementChild as HTMLInputElement
+        ).firstElementChild as HTMLInputElement
       ).checked,
       false
     );
@@ -400,7 +398,7 @@
       })
     );
 
-    const publishOnPush = valueOf('Publish comments on push', 'preferences')!
+    const publishOnPush = valueOf('Publish comments on push', 'preferences')
       .firstElementChild! as HTMLSpanElement;
 
     publishOnPush.click();
@@ -437,7 +435,7 @@
     const publishCommentsOnPush = valueOf(
       'Publish comments on push',
       'preferences'
-    )!.firstElementChild! as HTMLSpanElement;
+    ).firstElementChild! as HTMLSpanElement;
     publishCommentsOnPush.click();
 
     assert.isTrue(element.hasUnsavedChanges());
@@ -458,7 +456,7 @@
     const newChangesWorkInProgress = valueOf(
       'Set new changes to "work in progress" by default',
       'preferences'
-    )!.firstElementChild! as HTMLSpanElement;
+    ).firstElementChild! as HTMLSpanElement;
     newChangesWorkInProgress.click();
 
     assert.isTrue(element.hasUnsavedChanges());
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
index 1ea2a64..5541e87 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
@@ -72,9 +72,10 @@
     this.hidden = false;
 
     const url = this.buildAvatarURL(this.account);
-    if (url) {
-      this.style.backgroundImage = `url("${url}")`;
-    }
+    // Fallback to empty string to make sure that the user,
+    // which doesn't have an avatar set, does not reuse
+    // someone elses.
+    this.style.backgroundImage = url ? `url("${url}")` : '';
   }
 
   private getAccounts(account: AccountInfo) {
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
index 89b2a6e..ab649b7 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
@@ -38,7 +38,6 @@
   Comment,
   CommentThread,
   isDraft,
-  isRobot,
   NumericChangeId,
   RepoName,
   UrlEncodedCommentId,
@@ -404,9 +403,6 @@
         .comment-box.unresolved {
           background-color: var(--unresolved-comment-background-color);
         }
-        .comment-box.robotComment {
-          background-color: var(--robot-comment-background-color);
-        }
         #actionsContainer {
           display: flex;
         }
@@ -492,7 +488,6 @@
   override render() {
     if (!this.thread) return;
     const dynamicBoxClasses = {
-      robotComment: this.isRobotComment(),
       unresolved: this.unresolved,
       saving: this.saving,
     };
@@ -557,7 +552,6 @@
 
   private renderComment(comment?: Comment) {
     if (!comment) return nothing;
-    const robotButtonDisabled = !this.account || this.isDraft();
     const isFirstComment = this.getFirstComment() === comment;
     const initiallyCollapsed =
       !isDraft(comment) &&
@@ -570,7 +564,6 @@
         .comment=${comment}
         .comments=${this.thread!.comments}
         ?initially-collapsed=${initiallyCollapsed}
-        ?robot-button-disabled=${robotButtonDisabled}
         ?show-patchset=${this.showPatchset}
         ?show-ported-comment=${this.showPortedComment && isFirstComment}
         @reply-to-comment=${this.handleReplyToComment}
@@ -598,7 +591,7 @@
   }
 
   renderActions() {
-    if (!this.account || this.isDraft() || this.isRobotComment()) return;
+    if (!this.account || this.isDraft()) return;
     return html`
       <div id="actionsContainer">
         <span id="unresolvedLabel">${
@@ -881,10 +874,6 @@
     return '';
   }
 
-  private isRobotComment() {
-    return isRobot(this.getLastComment());
-  }
-
   private getFirstComment() {
     assertIsDefined(this.thread);
     return getFirstComment(this.thread);
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
index ababd89..44c8646 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
@@ -134,20 +134,14 @@
             <gr-comment
               collapsed=""
               initially-collapsed=""
-              robot-button-disabled=""
               show-patchset=""
             ></gr-comment>
             <gr-comment
               collapsed=""
               initially-collapsed=""
-              robot-button-disabled=""
               show-patchset=""
             ></gr-comment>
-            <gr-comment
-              class="draft"
-              robot-button-disabled=""
-              show-patchset=""
-            ></gr-comment>
+            <gr-comment class="draft" show-patchset=""></gr-comment>
           </div>
         </div>
       `
@@ -172,11 +166,7 @@
         <div id="container">
           <h3 class="assistive-tech-only">Draft Comment thread by Yoda</h3>
           <div class="comment-box" tabindex="0">
-            <gr-comment
-              class="draft"
-              robot-button-disabled=""
-              show-patchset=""
-            ></gr-comment>
+            <gr-comment class="draft" show-patchset=""></gr-comment>
           </div>
         </div>
       `
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
index a11c148..660b014 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
@@ -26,9 +26,7 @@
   DraftInfo,
   NumericChangeId,
   RepoName,
-  RobotCommentInfo,
   Comment,
-  isRobot,
   isSaving,
   isError,
   isDraft,
@@ -43,7 +41,6 @@
   hasUserSuggestion,
   id,
   isFileLevelComment,
-  NEWLINE_PATTERN,
   USER_SUGGESTION_START_PATTERN,
 } from '../../../utils/comment-util';
 import {
@@ -178,7 +175,7 @@
   comment?: Comment;
 
   // TODO: Move this out of gr-comment. gr-comment should not have a comments
-  // property. This is only used for hasHumanReply at the moment.
+  // property.
   @property({type: Array})
   comments?: Comment[];
 
@@ -202,9 +199,6 @@
   @property({type: Boolean, reflect: true})
   collapsed?: boolean;
 
-  @property({type: Boolean, attribute: 'robot-button-disabled'})
-  robotButtonDisabled = false;
-
   @property({type: String})
   messagePlaceholder?: string;
 
@@ -392,9 +386,6 @@
         this.save();
       });
     }
-    this.addEventListener('apply-user-suggestion', () => {
-      this.handleAppliedFix();
-    });
     this.addEventListener('open-user-suggest-preview', e => {
       this.handleShowFix(e.detail.code);
     });
@@ -561,18 +552,11 @@
         span.date:hover {
           text-decoration: underline;
         }
-        .actions,
-        .robotActions {
+        .actions {
           display: flex;
           justify-content: space-between;
           padding-top: 0;
         }
-        .robotActions {
-          /* Better than the negative margin would be to remove the gr-button
-       * padding, but then we would also need to fix the buttons that are
-       * inserted by plugins. :-/ */
-          margin: 4px 0 -4px;
-        }
         .action {
           margin-left: var(--spacing-l);
         }
@@ -593,16 +577,6 @@
         .show-hide {
           margin-left: var(--spacing-s);
         }
-        .robotId {
-          color: var(--deemphasized-text-color);
-          margin-bottom: var(--spacing-m);
-        }
-        .robotRun {
-          margin-left: var(--spacing-m);
-        }
-        .robotRunLink {
-          margin-left: var(--spacing-m);
-        }
         /* just for a11y */
         input.show-hide {
           display: none;
@@ -737,10 +711,9 @@
         <div id="container" class=${classMap(classes)}>
           ${this.renderHeader()}
           <div class="body">
-            ${this.renderRobotAuthor()} ${this.renderEditingTextarea()}
-            ${this.renderCommentMessage()}
+            ${this.renderEditingTextarea()} ${this.renderCommentMessage()}
             <gr-endpoint-slot name="above-actions"></gr-endpoint-slot>
-            ${this.renderHumanActions()} ${this.renderRobotActions()}
+            ${this.renderHumanActions()}
           </div>
           ${/* if this.editing */ this.renderGeneratedSuggestionPreview()}
           ${/* if !this.editing */ this.renderFixSuggestionPreview()}
@@ -763,19 +736,15 @@
           ${this.renderDraftLabel()}
         </div>
         <div class="headerMiddle">${this.renderCollapsedContent()}</div>
-        ${this.renderSuggestEditButton()} ${this.renderRunDetails()}
-        ${this.renderDeleteButton()} ${this.renderPatchset()}
-        ${this.renderSeparator()} ${this.renderDate()} ${this.renderToggle()}
+        ${this.renderSuggestEditButton()} ${this.renderDeleteButton()}
+        ${this.renderPatchset()} ${this.renderSeparator()} ${this.renderDate()}
+        ${this.renderToggle()}
       </div>
     `;
   }
 
   private renderAuthor() {
     if (isDraft(this.comment)) return;
-    if (isRobot(this.comment)) {
-      const id = this.comment.robot_id;
-      return html`<span class="robotName">${id}</span>`;
-    }
     return html`
       <gr-account-label .account=${this.comment?.author ?? this.account}>
       </gr-account-label>
@@ -825,26 +794,12 @@
     `;
   }
 
-  private renderRunDetails() {
-    if (!isRobot(this.comment)) return;
-    if (!this.comment?.url || this.collapsed) return;
-    return html`
-      <div class="runIdMessage message">
-        <div class="runIdInformation">
-          <a class="robotRunLink" href=${this.comment.url}>
-            <span class="robotRun link">Run Details</span>
-          </a>
-        </div>
-      </div>
-    `;
-  }
-
   /**
    * Deleting a comment is an admin feature. It means more than just discarding
    * a draft. It is an action applied to published comments.
    */
   private renderDeleteButton() {
-    if (!this.isAdmin || isDraft(this.comment) || isRobot(this.comment)) return;
+    if (!this.isAdmin || isDraft(this.comment)) return;
     if (this.collapsed) return;
     return html`
       <gr-button
@@ -918,11 +873,6 @@
     `;
   }
 
-  private renderRobotAuthor() {
-    if (!isRobot(this.comment) || this.collapsed) return;
-    return html`<div class="robotId">${this.comment.author?.name}</div>`;
-  }
-
   private renderEditingTextarea() {
     if (!this.editing || this.collapsed) return;
     return html`
@@ -1056,7 +1006,7 @@
   }
 
   private renderHumanActions() {
-    if (!this.account || isRobot(this.comment)) return;
+    if (!this.account) return;
     if (this.collapsed || !isDraft(this.comment)) return;
     return html`
       <div class="actions">
@@ -1158,13 +1108,9 @@
   }
 
   private renderFixSuggestionPreview() {
-    if (
-      !this.comment?.fix_suggestions ||
-      this.editing ||
-      isRobot(this.comment) ||
-      this.collapsed
-    )
+    if (!this.comment?.fix_suggestions || this.editing || this.collapsed) {
       return nothing;
+    }
     return html`<gr-fix-suggestions
       .comment=${this.comment}
     ></gr-fix-suggestions>`;
@@ -1345,51 +1291,6 @@
     };
   }
 
-  private renderRobotActions() {
-    if (!this.account || !isRobot(this.comment)) return;
-    const endpoint = html`
-      <gr-endpoint-decorator name="robot-comment-controls">
-        <gr-endpoint-param name="comment" .value=${this.comment}>
-        </gr-endpoint-param>
-      </gr-endpoint-decorator>
-    `;
-    return html`
-      <div class="robotActions">
-        ${this.renderCopyLinkIcon()} ${endpoint} ${this.renderShowFixButton()}
-        ${this.renderPleaseFixButton()}
-      </div>
-    `;
-  }
-
-  private renderShowFixButton() {
-    const fix_suggestions = (this.comment as RobotCommentInfo)?.fix_suggestions;
-    if (!fix_suggestions || fix_suggestions.length === 0) return;
-    return html`
-      <gr-button
-        link
-        secondary
-        class="action show-fix"
-        @click=${() => this.handleShowFix()}
-      >
-        Show Fix
-      </gr-button>
-    `;
-  }
-
-  private renderPleaseFixButton() {
-    if (this.hasHumanReply()) return;
-    return html`
-      <gr-button
-        link
-        ?disabled=${this.robotButtonDisabled}
-        class="action fix"
-        @click=${this.handlePleaseFix}
-      >
-        Please Fix
-      </gr-button>
-    `;
-  }
-
   private renderConfirmDialog() {
     return html`
       <dialog id="confirmDeleteModal" tabindex="-1">
@@ -1506,15 +1407,6 @@
     this.messageText = quote + this.messageText;
   }
 
-  // TODO: Move this out of gr-comment. gr-comment should not have a comments
-  // property.
-  private hasHumanReply() {
-    if (!this.comment || !this.comments) return false;
-    return this.comments.some(
-      c => c.in_reply_to && c.in_reply_to === this.comment?.id && !isRobot(c)
-    );
-  }
-
   // private, but visible for testing
   async createFixPreview(
     replacement?: string
@@ -1550,23 +1442,6 @@
         ],
       };
     }
-    if (
-      isRobot(this.comment) &&
-      this.comment.fix_suggestions &&
-      this.comment.fix_suggestions.length > 0
-    ) {
-      const id = this.comment.robot_id;
-      return {
-        fixSuggestions: this.comment.fix_suggestions.map(s => {
-          return {
-            ...s,
-            description: `${id ?? ''} - ${s.description ?? ''}`,
-          };
-        }),
-        patchNum: this.comment.patch_set,
-        onCloseFixPreviewCallbacks: [],
-      };
-    }
     throw new Error('unable to create preview fix event');
   }
 
@@ -1623,19 +1498,6 @@
     }
   }
 
-  private handlePleaseFix() {
-    const message = this.comment?.message;
-    assert(!!message, 'empty message');
-    const quoted = message.replace(NEWLINE_PATTERN, '\n> ');
-    const eventDetail: ReplyToCommentEventDetail = {
-      content: `> ${quoted}\n\nPlease fix.`,
-      userWantsToEdit: false,
-      unresolved: true,
-    };
-    // Handled by <gr-comment-thread>.
-    fire(this, 'reply-to-comment', eventDetail);
-  }
-
   private handleAppliedFix() {
     const message = this.comment?.message;
     assert(!!message, 'empty message');
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts
index 41c7c4e..7d3d38b 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts
@@ -12,7 +12,6 @@
   stubRestApi,
   query,
   pressKey,
-  listenOnce,
   mockPromise,
   waitUntilCalled,
   dispatch,
@@ -34,10 +33,8 @@
 import {
   createComment,
   createDraft,
-  createRobotComment,
   createNewDraft,
 } from '../../../test/test-data-generators';
-import {ReplyToCommentEvent} from '../../../types/events';
 import {GrConfirmDeleteCommentDialog} from '../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog';
 import {assertIsDefined} from '../../../utils/common-util';
 import {Key, Modifier} from '../../../utils/dom-util';
@@ -176,82 +173,6 @@
       );
     });
 
-    test('renders expanded robot', async () => {
-      element.initiallyCollapsed = false;
-      element.comment = createRobotComment();
-      await element.updateComplete;
-      assert.shadowDom.equal(
-        element,
-        /* HTML */ `
-          <gr-endpoint-decorator name="comment">
-            <gr-endpoint-param name="comment"></gr-endpoint-param>
-            <gr-endpoint-param name="editing"></gr-endpoint-param>
-            <gr-endpoint-param name="message"></gr-endpoint-param>
-            <gr-endpoint-param name="isDraft"></gr-endpoint-param>
-            <div class="container" id="container">
-              <div class="header" id="header">
-                <div class="headerLeft">
-                  <span class="robotName">robot-id-123</span>
-                </div>
-                <div class="headerMiddle"></div>
-                <span class="patchset-text">Patchset 1</span>
-                <span class="separator"></span>
-                <span class="date" tabindex="0">
-                  <gr-date-formatter withtooltip=""></gr-date-formatter>
-                </span>
-                <div class="show-hide" tabindex="0">
-                  <label aria-label="Collapse" class="show-hide">
-                    <input class="show-hide" type="checkbox" />
-                    <gr-icon id="icon" icon="expand_less"></gr-icon>
-                  </label>
-                </div>
-              </div>
-              <div class="body">
-                <div class="robotId"></div>
-                <gr-formatted-text class="message"></gr-formatted-text>
-                <gr-endpoint-slot name="above-actions"></gr-endpoint-slot>
-                <div class="robotActions">
-                  <gr-icon
-                    icon="link"
-                    class="copy link-icon"
-                    role="button"
-                    tabindex="0"
-                    title="Copy link to this comment"
-                  ></gr-icon>
-                  <gr-endpoint-decorator name="robot-comment-controls">
-                    <gr-endpoint-param name="comment"></gr-endpoint-param>
-                  </gr-endpoint-decorator>
-                  <gr-button
-                    aria-disabled="false"
-                    class="action show-fix"
-                    link=""
-                    role="button"
-                    secondary=""
-                    tabindex="0"
-                  >
-                    Show Fix
-                  </gr-button>
-                  <gr-button
-                    aria-disabled="false"
-                    class="action fix"
-                    link=""
-                    role="button"
-                    tabindex="0"
-                  >
-                    Please Fix
-                  </gr-button>
-                </div>
-              </div>
-            </div>
-          </gr-endpoint-decorator>
-          <dialog id="confirmDeleteModal" tabindex="-1">
-            <gr-confirm-delete-comment-dialog id="confirmDeleteCommentDialog">
-            </gr-confirm-delete-comment-dialog>
-          </dialog>
-        `
-      );
-    });
-
     test('renders expanded admin', async () => {
       element.initiallyCollapsed = false;
       element.isAdmin = true;
@@ -784,41 +705,6 @@
       assert.isTrue(discardStub.called);
       assert.isFalse(saveStub.called);
     });
-
-    test('handlePleaseFix fires reply-to-comment event', async () => {
-      const listener = listenOnce<ReplyToCommentEvent>(
-        element,
-        'reply-to-comment'
-      );
-      element.comment = createRobotComment();
-      element.comments = [element.comment];
-      await element.updateComplete;
-
-      queryAndAssert<GrButton>(element, '.fix').click();
-
-      const e = await listener;
-      assert.equal(e.detail.unresolved, true);
-      assert.equal(e.detail.userWantsToEdit, false);
-      assert.isTrue(e.detail.content.includes('Please fix.'));
-    });
-
-    test('do not show Please Fix button if human reply exists', async () => {
-      element.initiallyCollapsed = false;
-      const robotComment = createRobotComment();
-      element.comment = robotComment;
-      await element.updateComplete;
-
-      let actions = query(element, '.robotActions gr-button.fix');
-      assert.isOk(actions);
-
-      element.comments = [
-        robotComment,
-        {...createComment(), in_reply_to: robotComment.id},
-      ];
-      await element.updateComplete;
-      actions = query(element, '.robotActions gr-button.fix');
-      assert.isNotOk(actions);
-    });
   });
 
   suite('auto saving', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
index f3160fb..9a402e8 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
@@ -24,6 +24,7 @@
 import {when} from 'lit/directives/when.js';
 import {isMagicPath} from '../../../utils/path-list-util';
 import {fireNoBubble} from '../../../utils/event-util';
+import {classMap} from 'lit/directives/class-map.js';
 
 /**
  * Required values are text and value. mobileText and triggerText will
@@ -44,6 +45,7 @@
   disabled?: boolean;
   file?: NormalizedFileInfo;
   commentThreads?: CommentThread[];
+  deemphasizeReason?: string;
 }
 
 declare global {
@@ -168,6 +170,9 @@
             --selection-background-color
           );
         }
+        .topContent.deemphasized {
+          color: var(--deemphasized-text-color);
+        }
         gr-comments-summary {
           padding-left: var(--spacing-s);
         }
@@ -258,10 +263,19 @@
   private renderPaperItem(item: DropdownItem) {
     return html`
       <paper-item ?disabled=${item.disabled} data-value=${item.value}>
-        <div class="topContent">
+        <div
+          class=${classMap({
+            topContent: true,
+            deemphasized: !!item.deemphasizeReason,
+          })}
+        >
           <div>
             <span>${item.text}</span>
             ${when(
+              !!item.deemphasizeReason,
+              () => html`<span>| ${item.deemphasizeReason}</span>`
+            )}
+            ${when(
               item.commentThreads,
               () => html`<gr-comments-summary
                 .commentThreads=${item.commentThreads}
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
index 490f31b..ff702b6 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
@@ -51,6 +51,7 @@
   formatCommitMessageString,
   FormattingError,
 } from '../../../utils/commit-message-formatter-util';
+import {modalStyles} from '../../../styles/gr-modal-styles';
 
 const RESTORED_MESSAGE = 'Content restored from a previous edit.';
 const STORAGE_DEBOUNCE_INTERVAL_MS = 400;
@@ -78,6 +79,9 @@
   @query('iron-autogrow-textarea')
   private textarea?: IronAutogrowTextareaElement;
 
+  @query('#uploaderConfirmDialog')
+  private readonly uploaderConfirmDialog?: HTMLDialogElement;
+
   @property({type: String})
   content?: string;
 
@@ -125,6 +129,8 @@
 
   @state() patchNum?: RevisionPatchSetNum;
 
+  @state() isUploader = false;
+
   private readonly restApiService = getAppContext().restApiService;
 
   private readonly getChangeModel = resolve(this, changeModelToken);
@@ -178,6 +184,11 @@
       () => this.getChangeModel().patchNum$,
       x => (this.patchNum = x)
     );
+    subscribe(
+      this,
+      () => this.getChangeModel().isUploader$,
+      x => (this.isUploader = x)
+    );
   }
 
   override disconnectedCallback() {
@@ -205,6 +216,7 @@
       sharedStyles,
       formStyles,
       fontStyles,
+      modalStyles,
       css`
         :host {
           display: block;
@@ -303,6 +315,7 @@
         ${this.renderViewer()} ${this.renderEditor()} ${this.renderButtons()}
         <gr-endpoint-slot name="above-actions"></gr-endpoint-slot>
       </gr-endpoint-decorator>
+      ${this.renderUploaderConfirmDialog()}
     `;
   }
 
@@ -438,6 +451,31 @@
     `;
   }
 
+  private renderUploaderConfirmDialog() {
+    if (this.isUploader) return nothing;
+    return html`
+      <dialog id="uploaderConfirmDialog" tabindex="-1">
+        <gr-dialog
+          confirm-label="Continue"
+          @confirm=${this.handleUploaderConfirm}
+          @cancel=${this.handleUploaderCancel}
+        >
+          <div class="header" slot="header">Become Uploader</div>
+          <div class="main" slot="main">
+            <p>
+              By editing the commit message, you will become the uploader of
+              the<br />
+              new patch set. This means that your own approvals will be
+              ignored<br />
+              for submit requirements that ignore uploader approvals.
+            </p>
+            <p>Do you want to continue?</p>
+          </div>
+        </gr-dialog>
+      </dialog>
+    `;
+  }
+
   contentChanged() {
     /* A changed content means that either a different change has been loaded
      * or new content was saved. Either way, let's reset the component.
@@ -604,13 +642,17 @@
           patchNum: this.patchNum,
         })
       );
-
       return;
     }
+
     await this.loadEmails();
-    this.editing = true;
-    await this.updateComplete;
-    this.focusTextarea();
+
+    if (!this.isUploader) {
+      assertIsDefined(this.uploaderConfirmDialog, 'uploaderConfirmDialog');
+      this.uploaderConfirmDialog.showModal();
+    } else {
+      this.startEditing();
+    }
   }
 
   async loadEmails() {
@@ -741,4 +783,22 @@
       return true;
     });
   }
+
+  private handleUploaderConfirm() {
+    assertIsDefined(this.uploaderConfirmDialog, 'uploaderConfirmDialog');
+    this.uploaderConfirmDialog.close();
+    this.startEditing();
+  }
+
+  private handleUploaderCancel() {
+    assertIsDefined(this.uploaderConfirmDialog, 'uploaderConfirmDialog');
+    this.uploaderConfirmDialog.close();
+  }
+
+  private startEditing() {
+    this.editing = true;
+    this.updateComplete.then(() => {
+      this.focusTextarea();
+    });
+  }
 }
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.ts b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.ts
index 323bf11..d45a34b 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.ts
@@ -23,6 +23,7 @@
 } from '../../../api/rest-api';
 import {changeViewModelToken} from '../../../models/views/change';
 import {IronAutogrowTextareaElement} from '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
+import {GrDialog} from '../gr-dialog/gr-dialog';
 
 const emails = [
   {
@@ -41,6 +42,7 @@
 
   setup(async () => {
     element = await fixture(html`<gr-editable-content></gr-editable-content>`);
+    element.isUploader = true;
     await element.updateComplete;
     storageService = testResolver(storageServiceToken);
   });
@@ -463,4 +465,38 @@
       assert.include(formatButton.title, 'Automatically fixes formatting');
     });
   });
+
+  suite('uploader confirm dialog', () => {
+    test('shows when user is not uploader', async () => {
+      element.isUploader = false;
+      element.editing = true;
+      await element.updateComplete;
+      const dialog = queryAndAssert<GrDialog>(
+        element,
+        '#uploaderConfirmDialog'
+      );
+      assert.dom.equal(
+        dialog,
+        `
+          <dialog id="uploaderConfirmDialog" tabindex="-1">
+            <gr-dialog confirm-label="Continue">
+              <div class="header" slot="header">Become Uploader</div>
+              <div class="main" slot="main">
+                <p>
+                  By editing the commit message, you will become the uploader of
+              the
+                  <br />
+                  new patch set. This means that your own approvals will be
+              ignored
+                  <br />
+                  for submit requirements that ignore uploader approvals.
+                </p>
+                <p>Do you want to continue?</p>
+              </div>
+            </gr-dialog>
+          </dialog>
+        `
+      );
+    });
+  });
 });
diff --git a/polygerrit-ui/app/elements/shared/gr-fix-suggestions/gr-fix-suggestions.ts b/polygerrit-ui/app/elements/shared/gr-fix-suggestions/gr-fix-suggestions.ts
index 63ec4d1..c25af83 100644
--- a/polygerrit-ui/app/elements/shared/gr-fix-suggestions/gr-fix-suggestions.ts
+++ b/polygerrit-ui/app/elements/shared/gr-fix-suggestions/gr-fix-suggestions.ts
@@ -26,6 +26,7 @@
 import {getAppContext} from '../../../services/app-context';
 import {Interaction} from '../../../constants/reporting';
 import {ChangeStatus, FixSuggestionInfo} from '../../../api/rest-api';
+import {ReportSource} from '../../../services/suggestions/suggestions-service';
 
 export const COLLAPSE_SUGGESTION_STORAGE_KEY = 'collapseSuggestionStorageKey';
 
@@ -295,7 +296,11 @@
         fixApplied => {
           if (fixApplied)
             fire(this, 'apply-user-suggestion', {
-              fixSuggestion: fixSuggestions?.[0],
+              fixSuggestion: fixSuggestions?.[0]?.description?.includes(
+                ReportSource.GET_AI_FIX_FOR_COMMENT
+              )
+                ? fixSuggestions?.[0]
+                : undefined,
             });
         },
       ],
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
index fa2a4ff..08e39c4 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
@@ -25,6 +25,11 @@
 } from '../../../utils/comment-util';
 import {sameOrigin} from '../../../utils/url-util';
 
+// MIME types for images we allow showing. Do not include SVG, it can contain
+// arbitrary JavaScript.
+const IMAGE_MIME_PATTERN =
+  /^data:image\/(bmp|gif|x-icon|jpeg|jpg|png|tiff|webp);base64,/;
+
 /**
  * This element optionally renders markdown and also applies some regex
  * replacements to linkify key parts of the text defined by the host's config.
@@ -48,6 +53,9 @@
   @state()
   MARKDOWN_LIMIT = 100000;
 
+  @state()
+  private allowMarkdownBase64ImagesInComments = false;
+
   /**
    * Note: Do not use sharedStyles or other styles here that should not affect
    * the generated HTML of the markdown.
@@ -131,6 +139,55 @@
           link: '$1',
           enabled: true,
         };
+
+        // List of common TLDs to specifically match for schemeless URLs.
+        const TLD_REGEX = [
+          'com',
+          'org',
+          'net',
+          'edu',
+          'gov',
+          'co',
+          'jp',
+          'de',
+          'uk',
+          'fr',
+          'us',
+          'io',
+        ].join('|');
+
+        // Linkify schemeless URLs with proper domain structures.
+        this.repoCommentLinks['ALWAYS_LINK_SCHEMELESS'] = {
+          // (?<=\s|^|[('":[])   // Ensure the match is preceded by whitespace,
+          //                     // start of line, or one of ( ' " : [
+          // (                   // Start capture group 1
+          //   (?:               // Start non-capturing domain group
+          //     [\w-]+\.        //   Sequence of words/hyphens with dot, e.g. "a-b."
+          //   )+                // End domain group. Require at least one match
+          //   (?:${TLD_REGEX})  // Ensure the match ends with a common TLD
+          //   (?=.*?/)          // Positive lookahead to ensure a '/' exists in the path/query/fragment
+          //   (?:               // Start non-capturing path/query/fragment group
+          //     [/?#]           //   Start with one of / ? #
+          //     [^\s'"]*        //   Followed by some chars that are not whitespace,
+          //                     //   ' or " (to not grab trailing quotes)
+          //   )                 // End path/query/fragment group
+          // )                   // End capture group 1
+          // (?=\s|$|[)'"!?.,])  // Ensure the match is followed by whitespace,
+          //                     // end of line, or one of ) ' " ! ? . ,
+          match: `(?<=\\s|^|[('":[])((?:[\\w-]+\\.)+(?:${TLD_REGEX})(?=.*?/)(?:[/?#][^\\s'"]*))(?=\\s|$|[)'"!?.,])`,
+          // Prepend http:// for the link href otherwise it will be treated as
+          // a relative URL.
+          link: 'http://$1',
+          enabled: true,
+        };
+      }
+    );
+
+    subscribe(
+      this,
+      () => this.getConfigModel().allowMarkdownBase64ImagesInComments$,
+      allow => {
+        this.allowMarkdownBase64ImagesInComments = allow;
       }
     );
   }
@@ -184,6 +241,9 @@
       return `<p>${linkedText}</p>`;
     };
 
+    const allowMarkdownBase64ImagesInComments =
+      this.allowMarkdownBase64ImagesInComments;
+
     // We are overriding some marked-element renderers for a few reasons:
     // 1. Disable inline images as a design/policy choice.
     // 2. Inline code blocks ("codespan") do not unescape HTML characters when
@@ -216,8 +276,19 @@
           >${text}</a
         >`;
       };
-      renderer['image'] = (href: string, _title: string, text: string) =>
-        `![${text}](${href})`;
+      renderer['image'] = (href: string, title: string, text: string) => {
+        // Check if this is a base64-encoded image
+        if (
+          allowMarkdownBase64ImagesInComments &&
+          IMAGE_MIME_PATTERN.test(href)
+        ) {
+          return `<img src="${href}" alt="${text}" ${
+            title ? `title="${title}"` : ''
+          } />`;
+        }
+        // For non-base64 images just return the markdown
+        return `![${text}](${href})`;
+      };
       renderer['codespan'] = (text: string) =>
         `<code>${unescapeHTML(text)}</code>`;
       renderer['code'] = (text: string, infostring: string) => {
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
index 723267e..1694fcd 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
@@ -16,7 +16,11 @@
 import './gr-formatted-text';
 import {GrFormattedText} from './gr-formatted-text';
 import {createComment, createConfig} from '../../../test/test-data-generators';
-import {queryAndAssert, waitUntilObserved} from '../../../test/test-utils';
+import {
+  query,
+  queryAndAssert,
+  waitUntilObserved,
+} from '../../../test/test-utils';
 import {CommentLinks, EmailAddress} from '../../../api/rest-api';
 import {testResolver} from '../../../test/common-test-setup';
 import {GrAccountChip} from '../gr-account-chip/gr-account-chip';
@@ -236,12 +240,28 @@
     });
 
     test('does default linking', async () => {
-      const checkLinking = async (url: string) => {
+      const checkLinking = async (url: string, expectLinkified = true) => {
         element.content = url;
         await element.updateComplete;
-        const a = queryAndAssert<HTMLElement>(element, 'a');
-        assert.equal(a.getAttribute('href'), url);
-        assert.equal(a.innerText, url);
+        const a = query<HTMLElement>(element, 'a');
+
+        if (expectLinkified) {
+          assert.isDefined<HTMLElement | undefined>(a);
+          // URLs without scheme are upgraded to https:// by the
+          // ALWAYS_LINK_SCHEMELESS rule. URLs with http:// or https://
+          // are preserved by the ALWAYS_LINK_HTTP rule.
+          const isSchemeless =
+            !url.startsWith('http://') &&
+            !url.startsWith('https://') &&
+            !url.startsWith('mailto:') &&
+            !url.startsWith('/');
+          const expectedHref = isSchemeless ? `http://${url}` : url;
+
+          assert.equal(a.getAttribute('href'), expectedHref);
+          assert.equal(a.innerText, url);
+        } else {
+          assert.isUndefined(a);
+        }
       };
 
       await checkLinking('http://www.google.com');
@@ -254,6 +274,18 @@
       await checkLinking(
         'https://google.com/traces/list?project=gerrit&tid=123'
       );
+
+      await checkLinking('www.google.com/path');
+      await checkLinking('www.google-foo.com/path');
+      await checkLinking('google.co.uk/path?q=1#frag');
+
+      // Do not linkify URLs without `/`.
+      await checkLinking('google.com', false);
+      await checkLinking('com.google.gerrit.server.Event', false);
+
+      // Do not linkify URLs without a recognized TLD.
+      await checkLinking('google.foogle/path', false);
+      await checkLinking('google.com.blah/path', false);
     });
   });
 
@@ -743,13 +775,29 @@
     });
 
     test('does default linking', async () => {
-      const checkLinking = async (url: string) => {
+      const checkLinking = async (url: string, expectLinkified = true) => {
         element.content = url;
         await element.updateComplete;
-        const a = queryAndAssert<HTMLElement>(element, 'a');
+        const a = query<HTMLElement>(element, 'a');
         const p = queryAndAssert<HTMLElement>(element, 'p');
-        assert.equal(a.getAttribute('href'), url);
         assert.equal(p.innerText, url);
+
+        if (expectLinkified) {
+          assert.isDefined<HTMLElement | undefined>(a);
+          // URLs without scheme are upgraded to https:// by the
+          // ALWAYS_LINK_SCHEMELESS rule. URLs with http:// or https://
+          // are preserved by the ALWAYS_LINK_HTTP rule.
+          const isSchemeless =
+            !url.startsWith('http://') &&
+            !url.startsWith('https://') &&
+            !url.startsWith('mailto:') &&
+            !url.startsWith('/');
+          const expectedHref = isSchemeless ? `http://${url}` : url;
+
+          assert.equal(a.getAttribute('href'), expectedHref);
+        } else {
+          assert.isUndefined(a);
+        }
       };
 
       await checkLinking('http://www.google.com');
@@ -759,6 +807,18 @@
       await checkLinking(
         'https://google.com/traces/list?project=gerrit&tid=123'
       );
+
+      await checkLinking('www.google.com/path');
+      await checkLinking('www.google-foo.com/path');
+      await checkLinking('google.co.uk/path?q=1#frag');
+
+      // Do not linkify URLs without `/`.
+      await checkLinking('google.com', false);
+      await checkLinking('com.google.gerrit.server.Event', false);
+
+      // Do not linkify URLs without a recognized TLD.
+      await checkLinking('google.foogle/path', false);
+      await checkLinking('google.com.blah/path', false);
     });
 
     suite('user suggest fix', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts
index b2fed78..c766c26 100644
--- a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts
@@ -38,7 +38,7 @@
 
   test('focusOnCopy', async () => {
     const focusStub = sinon.stub(
-      queryAndAssert<GrCopyClipboard>(element, 'gr-copy-clipboard')!,
+      queryAndAssert<GrCopyClipboard>(element, 'gr-copy-clipboard'),
       'focusOnCopy'
     );
     await element.focusOnCopy();
diff --git a/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview.ts b/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview.ts
index 6d5172eb..c451bc2 100644
--- a/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview.ts
+++ b/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview.ts
@@ -34,6 +34,7 @@
 import {createChangeUrl} from '../../../models/views/change';
 import {getFileExtension} from '../../../utils/file-util';
 import {throwingErrorCallback} from '../gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper';
+import {ReportSource} from '../../../services/suggestions/suggestions-service';
 
 export interface PreviewLoadedDetail {
   previewLoadedFor?: FixSuggestionInfo;
@@ -314,7 +315,13 @@
         })
       );
       fire(this, 'reload-diff', {path: fixSuggestion.replacements[0].path});
-      fire(this, 'apply-user-suggestion', {fixSuggestion});
+      fire(this, 'apply-user-suggestion', {
+        fixSuggestion: fixSuggestion.description.includes(
+          ReportSource.GET_AI_FIX_FOR_COMMENT
+        )
+          ? fixSuggestion
+          : undefined,
+      });
     }
   }
 
diff --git a/polygerrit-ui/app/elements/shared/gr-suggestion-textarea/gr-suggestion-textarea.ts b/polygerrit-ui/app/elements/shared/gr-suggestion-textarea/gr-suggestion-textarea.ts
index d0f6917..4f9a6f4 100644
--- a/polygerrit-ui/app/elements/shared/gr-suggestion-textarea/gr-suggestion-textarea.ts
+++ b/polygerrit-ui/app/elements/shared/gr-suggestion-textarea/gr-suggestion-textarea.ts
@@ -116,6 +116,10 @@
 
   @state() suggestions: (Item | EmojiSuggestion)[] = [];
 
+  @state() private isDragging = false;
+
+  @state() private allowMarkdownBase64ImagesInComments = false;
+
   // Accessed in tests.
   readonly reporting = getAppContext().reportingService;
 
@@ -141,6 +145,10 @@
 
   constructor() {
     super();
+    this.addEventListener('dragenter', this.handleDragEnter);
+    this.addEventListener('dragover', this.handleDragOver);
+    this.addEventListener('dragleave', this.handleDragLeave);
+    this.addEventListener('drop', this.handleDrop);
     subscribe(
       this,
       () => this.getChangeModel().changeNum$,
@@ -153,6 +161,13 @@
         this.serverConfig = config;
       }
     );
+    subscribe(
+      this,
+      () => this.getConfigModel().allowMarkdownBase64ImagesInComments$,
+      allow => {
+        this.allowMarkdownBase64ImagesInComments = allow;
+      }
+    );
     this.shortcuts.addLocal({key: Key.UP}, e => this.handleUpKey(e), {
       preventDefault: false,
     });
@@ -245,6 +260,13 @@
           width: 100%;
           white-space: pre-wrap;
         }
+        :host {
+          display: block;
+        }
+        :host([data-dragging]) {
+          border: 2px dashed var(--border-color);
+          background-color: var(--background-color-secondary);
+        }
       `,
     ];
   }
@@ -308,6 +330,13 @@
       this.fireChangedEvents();
       this.handleTextChanged();
     }
+    if (changedProperties.has('isDragging')) {
+      if (this.isDragging) {
+        this.setAttribute('data-dragging', '');
+      } else {
+        this.removeAttribute('data-dragging');
+      }
+    }
   }
 
   // private but used in test
@@ -686,6 +715,58 @@
   isTextareaFocused() {
     return !!this.textarea?.isFocused;
   }
+
+  private handleDragEnter(e: DragEvent) {
+    if (!this.allowMarkdownBase64ImagesInComments) return;
+    e.preventDefault();
+    this.isDragging = true;
+  }
+
+  private handleDragOver(e: DragEvent) {
+    if (!this.allowMarkdownBase64ImagesInComments) return;
+    e.preventDefault();
+    e.dataTransfer!.dropEffect = 'copy';
+  }
+
+  private handleDragLeave(e: DragEvent) {
+    if (!this.allowMarkdownBase64ImagesInComments) return;
+    e.preventDefault();
+    this.isDragging = false;
+  }
+
+  private async handleDrop(e: DragEvent) {
+    if (!this.allowMarkdownBase64ImagesInComments) return;
+    e.preventDefault();
+    this.isDragging = false;
+
+    const files = e.dataTransfer?.files;
+    if (!files?.length) return;
+
+    const file = files[0];
+    if (!file.type.startsWith('image/')) {
+      console.warn('Only image files are supported');
+      return;
+    }
+
+    try {
+      const base64 = await this.fileToBase64(file);
+      const imageMarkdown = `![${file.name}](${base64})`;
+
+      // Add the image markdown to the text
+      this.text = this.text ? `${this.text}\n${imageMarkdown}` : imageMarkdown;
+    } catch (err) {
+      console.error('Error processing dropped image:', err);
+    }
+  }
+
+  private fileToBase64(file: File): Promise<string> {
+    return new Promise((resolve, reject) => {
+      const reader = new FileReader();
+      reader.onload = () => resolve(reader.result as string);
+      reader.onerror = reject;
+      reader.readAsDataURL(file);
+    });
+  }
 }
 
 declare global {
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.ts b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.ts
index 265ffb7..03daa81 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.ts
@@ -44,21 +44,21 @@
 
   test('the correct arrow is displayed', async () => {
     assert.equal(
-      getComputedStyle(queryAndAssert(element, '.arrowPositionBelow')!).display,
+      getComputedStyle(queryAndAssert(element, '.arrowPositionBelow')).display,
       'none'
     );
     assert.notEqual(
-      getComputedStyle(queryAndAssert(element, '.arrowPositionAbove')!).display,
+      getComputedStyle(queryAndAssert(element, '.arrowPositionAbove')).display,
       'none'
     );
     element.positionBelow = true;
     await element.updateComplete;
     assert.notEqual(
-      getComputedStyle(queryAndAssert(element, '.arrowPositionBelow')!).display,
+      getComputedStyle(queryAndAssert(element, '.arrowPositionBelow')).display,
       'none'
     );
     assert.equal(
-      getComputedStyle(queryAndAssert(element, '.arrowPositionAbove')!).display,
+      getComputedStyle(queryAndAssert(element, '.arrowPositionAbove')).display,
       'none'
     );
   });
diff --git a/polygerrit-ui/app/elements/shared/gr-vote-chip/gr-vote-chip.ts b/polygerrit-ui/app/elements/shared/gr-vote-chip/gr-vote-chip.ts
index 02bde24..84b42b7 100644
--- a/polygerrit-ui/app/elements/shared/gr-vote-chip/gr-vote-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-vote-chip/gr-vote-chip.ts
@@ -4,7 +4,7 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 import '../gr-tooltip-content/gr-tooltip-content';
-import {LitElement, css, html} from 'lit';
+import {LitElement, TemplateResult, css, html} from 'lit';
 import {customElement, property} from 'lit/decorators.js';
 import {
   ApprovalInfo,
@@ -127,7 +127,7 @@
 
     return html`<gr-tooltip-content
       class="container ${this.more ? 'more' : ''}"
-      title=${this.computeTooltip()}
+      title=${this.computeTooltip(renderValue)}
       has-tooltip
     >
       <div class="vote-chip ${this.computeClass()}">${renderValue}</div>
@@ -173,12 +173,14 @@
     }
   }
 
-  private computeTooltip() {
+  private computeTooltip(renderValue: string | TemplateResult<1>) {
     if (!this.label || !isDetailedLabelInfo(this.label)) {
       return '';
     }
     const voteDescription =
-      this.label.values?.[valueString(this.vote?.value)] ?? '';
+      typeof renderValue === 'string'
+        ? this.label.values?.[renderValue] ?? ''
+        : '';
 
     if (this.tooltipWithWhoVoted && this.vote) {
       return `${this.vote?.name}: ${voteDescription}`;
diff --git a/polygerrit-ui/app/models/change/change-model.ts b/polygerrit-ui/app/models/change/change-model.ts
index bd42baf..6febeff 100644
--- a/polygerrit-ui/app/models/change/change-model.ts
+++ b/polygerrit-ui/app/models/change/change-model.ts
@@ -18,6 +18,7 @@
   RevisionInfo,
   ListChangesOption,
   ChangeViewChangeInfo,
+  FileInfo,
 } from '../../types/common';
 import {ChangeStatus, DefaultBase} from '../../constants/constants';
 import {combineLatest, from, Observable, forkJoin, of} from 'rxjs';
@@ -35,7 +36,12 @@
   findEdit,
   sortRevisions,
 } from '../../utils/patch-set-util';
-import {isDefined, LoadingStatus, ParsedChangeInfo} from '../../types/types';
+import {
+  EditRevisionInfo,
+  isDefined,
+  LoadingStatus,
+  ParsedChangeInfo,
+} from '../../types/types';
 import {fireAlert, fireTitleChange} from '../../utils/event-util';
 import {RestApiService} from '../../services/gr-rest-api/gr-rest-api';
 import {select} from '../../utils/observable-util';
@@ -43,7 +49,11 @@
 import {Model} from '../base/model';
 import {UserModel} from '../user/user-model';
 import {define} from '../dependency';
-import {isOwner, listChangesOptionsToHex} from '../../utils/change-util';
+import {
+  isOwner,
+  isUploader,
+  listChangesOptionsToHex,
+} from '../../utils/change-util';
 import {
   ChangeChildView,
   ChangeViewModel,
@@ -81,6 +91,101 @@
   mergeable?: boolean;
 }
 
+export enum RevisionFileUpdateStatus {
+  // Indicates request error.
+  UNKNOWN = 'UNKNOWN',
+  // File is identical to previous patchset
+  SAME = 'SAME',
+  // File has been changed in comparison to previous patchset.
+  MODIFIED = 'MODIFIED',
+}
+
+export type RevisionUpdatedFiles = {
+  [revisionId: string]: {[filename: string]: RevisionFileUpdateStatus};
+};
+
+/**
+ * Calculates whether the file is modified in relation to the previous patchset.
+ *
+ * The comparison is done based on SHA-1 of file contents.
+ */
+function computeRevisionFileUpdateStatus(
+  filename: string,
+  info: FileInfo | undefined,
+  prevRevId: string | undefined,
+  fileInfos: {[revId: string]: {[filename: string]: FileInfo}}
+) {
+  // The file info is missing means it's not changed vs. patchset base.
+  if (!info) {
+    if (!prevRevId) {
+      return RevisionFileUpdateStatus.SAME;
+    } else {
+      // Check if modified in previous patchset, but not in current.
+      return filename in fileInfos[prevRevId]
+        ? RevisionFileUpdateStatus.MODIFIED
+        : RevisionFileUpdateStatus.SAME;
+    }
+  }
+
+  if (!prevRevId || !(filename in fileInfos[prevRevId])) {
+    return RevisionFileUpdateStatus.MODIFIED;
+  }
+
+  const prevSha = fileInfos[prevRevId][filename].new_sha;
+  if (!!info.new_sha && !!prevSha) {
+    return info.new_sha === prevSha
+      ? RevisionFileUpdateStatus.SAME
+      : RevisionFileUpdateStatus.MODIFIED;
+  }
+  return RevisionFileUpdateStatus.UNKNOWN;
+}
+
+/**
+ * For every revision and every file calculates if that file is modified when
+ * compared to the previous revision.
+ *
+ * The comparison is done based on SHA-1 of file contents.
+ *
+ * @param fileInfos for every revision contains the list FileInfo of files which
+ *   are modified compared to the revision's parent.
+ */
+export function computeRevisionUpdatedFiles(
+  change: ParsedChangeInfo | undefined,
+  fileInfos: {[revId: string]: {[filename: string]: FileInfo}} | undefined
+): RevisionUpdatedFiles | undefined {
+  if (!change || !fileInfos) {
+    // We set change to undefined when user navigates away from change
+    // page. So we should reset state to undefined in this case.
+    return undefined;
+  }
+  const patchsetToRevision: {[ps: number]: string} = {};
+  const revisionToPatchset: {[revId: string]: number} = {};
+  const allFiles = new Set<string>();
+  for (const [revId, rev] of Object.entries<RevisionInfo | EditRevisionInfo>(
+    change.revisions
+  )) {
+    revisionToPatchset[revId] = rev._number as number;
+    patchsetToRevision[rev._number as number] = revId;
+    Object.keys(fileInfos[revId] ?? {}).forEach(x => allFiles.add(x));
+  }
+  const revisionUpdatedFiles: RevisionUpdatedFiles = {};
+  for (const [revId, files] of Object.entries(fileInfos)) {
+    revisionUpdatedFiles[revId] = {};
+    const ps = revisionToPatchset[revId];
+    const prevRevId = ps === 1 ? undefined : patchsetToRevision[ps - 1];
+    for (const filename of allFiles) {
+      const info = files[filename];
+      revisionUpdatedFiles[revId][filename] = computeRevisionFileUpdateStatus(
+        filename,
+        info,
+        prevRevId,
+        fileInfos
+      );
+    }
+  }
+  return revisionUpdatedFiles;
+}
+
 /**
  * `change.revisions` is a dictionary mapping the revision sha to RevisionInfo,
  * but the info object itself does not contain the sha, which is a problem when
@@ -273,6 +378,28 @@
   );
 
   /**
+   * For every filename F and every revision R (corresponding to patchset P),
+   * stores whether the file is modified in relation to patchset P - 1 (or base
+   * if P = 1).
+   */
+  public readonly revisionUpdatedFiles$: Observable<
+    RevisionUpdatedFiles | undefined
+  > = select(
+    this.change$.pipe(
+      switchMap(change => {
+        if (!change) {
+          return of([change, undefined]);
+        }
+        return forkJoin([
+          Promise.resolve(change),
+          this.restApiService.getAllRevisionFiles(change._number),
+        ]);
+      })
+    ),
+    ([change, fileInfos]) => computeRevisionUpdatedFiles(change, fileInfos)
+  );
+
+  /**
    * Emits the current patchset number. If the route does not define the current
    * patchset num, then this selector waits for the change to be defined and
    * returns the number of the latest patchset.
@@ -316,6 +443,8 @@
 
   public readonly isOwner$: Observable<boolean>;
 
+  public readonly isUploader$: Observable<boolean>;
+
   public readonly messages$;
 
   public readonly revertingChangeIds$;
@@ -386,6 +515,10 @@
       combineLatest([this.change$, this.userModel.account$]),
       ([change, account]) => isOwner(change, account)
     );
+    this.isUploader$ = select(
+      combineLatest([this.change$, this.userModel.account$]),
+      ([change, account]) => isUploader(change, account)
+    );
     this.messages$ = select(this.change$, change => change?.messages);
     this.revertingChangeIds$ = select(this.messages$, messages =>
       getRevertCreatedChangeIds(messages ?? [])
diff --git a/polygerrit-ui/app/models/change/change-model_test.ts b/polygerrit-ui/app/models/change/change-model_test.ts
index 29113bc..854ad50 100644
--- a/polygerrit-ui/app/models/change/change-model_test.ts
+++ b/polygerrit-ui/app/models/change/change-model_test.ts
@@ -13,6 +13,7 @@
   createChangeMessageInfo,
   createChangeViewState,
   createEditInfo,
+  createFileInfo,
   createMergeable,
   createParsedChange,
   createRevision,
@@ -40,6 +41,8 @@
 import {getAppContext} from '../../services/app-context';
 import {
   ChangeState,
+  computeRevisionUpdatedFiles,
+  RevisionFileUpdateStatus,
   updateChangeWithEdit,
   updateRevisionsWithCommitShas,
 } from './change-model';
@@ -99,6 +102,122 @@
   });
 });
 
+suite('computeRevisionUpdatedFiles() tests', () => {
+  test('undefined change', async () => {
+    assert.isUndefined(updateChangeWithEdit());
+  });
+
+  test('calculate status for all files and revisions', async () => {
+    const change = {
+      ...createChange(),
+      revisions: {
+        rev1: createRevision(1),
+        rev2: createRevision(2),
+        rev3: createRevision(3),
+      },
+      current_revision: 'rev3' as CommitId,
+    };
+    const fileInfos = {
+      rev1: {
+        'a.txt': {
+          ...createFileInfo('a.txt'),
+          old_sha: 'sha00',
+          new_sha: 'sha01',
+        },
+        'c.txt': {
+          ...createFileInfo('c.txt'),
+          old_sha: 'sha20',
+          new_sha: 'sha21',
+        },
+      },
+      rev2: {
+        'a.txt': {
+          ...createFileInfo('a.txt'),
+          old_sha: 'sha00',
+          new_sha: 'sha01',
+        },
+        'b.txt': {
+          ...createFileInfo('b.txt'),
+          old_sha: 'sha10',
+          new_sha: 'sha11',
+        },
+      },
+      rev3: {
+        'a.txt': {
+          ...createFileInfo('a.txt'),
+          old_sha: 'sha00',
+          new_sha: 'sha02',
+        },
+        'b.txt': {
+          ...createFileInfo('b.txt'),
+          old_sha: 'sha10',
+          new_sha: 'sha11',
+        },
+        'c.txt': {
+          ...createFileInfo('c.txt'),
+          old_sha: 'sha20',
+          new_sha: 'sha21',
+        },
+      },
+    };
+    const result = computeRevisionUpdatedFiles(change, fileInfos);
+    assert.deepEqual(result, {
+      rev1: {
+        'a.txt': RevisionFileUpdateStatus.MODIFIED,
+        'b.txt': RevisionFileUpdateStatus.SAME,
+        'c.txt': RevisionFileUpdateStatus.MODIFIED,
+      },
+      rev2: {
+        'a.txt': RevisionFileUpdateStatus.SAME,
+        'b.txt': RevisionFileUpdateStatus.MODIFIED,
+        'c.txt': RevisionFileUpdateStatus.MODIFIED,
+      },
+      rev3: {
+        'a.txt': RevisionFileUpdateStatus.MODIFIED,
+        'b.txt': RevisionFileUpdateStatus.SAME,
+        'c.txt': RevisionFileUpdateStatus.MODIFIED,
+      },
+    });
+  });
+
+  test('no known sha, status unknown', async () => {
+    const change = {
+      ...createChange(),
+      revisions: {
+        rev1: createRevision(1),
+        rev2: createRevision(2),
+      },
+      current_revision: 'rev2' as CommitId,
+    };
+    const fileInfos = {
+      rev1: {
+        'a.txt': {
+          ...createFileInfo('a.txt'),
+          old_sha: undefined,
+          new_sha: undefined,
+        },
+      },
+      rev2: {
+        'a.txt': {
+          ...createFileInfo('a.txt'),
+          old_sha: 'sha00',
+          new_sha: 'sha01',
+        },
+      },
+    };
+    const result = computeRevisionUpdatedFiles(change, fileInfos);
+    assert.deepEqual(result, {
+      rev1: {
+        // Presence in fileInfos indicate change against BASE
+        'a.txt': RevisionFileUpdateStatus.MODIFIED,
+      },
+      rev2: {
+        'a.txt': RevisionFileUpdateStatus.UNKNOWN,
+      },
+    });
+  });
+});
+
 suite('change model tests', () => {
   let changeViewModel: ChangeViewModel;
   let changeModel: ChangeModel;
diff --git a/polygerrit-ui/app/models/checks/checks-model_test.ts b/polygerrit-ui/app/models/checks/checks-model_test.ts
index fdaacd2..8a0f8e3 100644
--- a/polygerrit-ui/app/models/checks/checks-model_test.ts
+++ b/polygerrit-ui/app/models/checks/checks-model_test.ts
@@ -281,7 +281,7 @@
     );
     assert.equal(
       current.runs[0].results![0].summary,
-      RUNS[0]!.results![0].summary
+      RUNS[0].results![0].summary
     );
     const result = RUNS[0].results![0];
     const updatedResult = {...result, summary: 'new'};
diff --git a/polygerrit-ui/app/models/comments/comments-model.ts b/polygerrit-ui/app/models/comments/comments-model.ts
index f11e352..2a59c27 100644
--- a/polygerrit-ui/app/models/comments/comments-model.ts
+++ b/polygerrit-ui/app/models/comments/comments-model.ts
@@ -9,8 +9,6 @@
   NumericChangeId,
   RevisionId,
   UrlEncodedCommentId,
-  RobotCommentInfo,
-  PathToRobotCommentsInfoMap,
   AccountInfo,
   DraftInfo,
   Comment,
@@ -74,8 +72,6 @@
 export interface CommentState {
   /** undefined means 'still loading' */
   comments?: {[path: string]: CommentInfo[]};
-  /** undefined means 'still loading' */
-  robotComments?: {[path: string]: RobotCommentInfo[]};
   // All drafts are DraftInfo objects and have `state` state set.
   /** undefined means 'still loading' */
   drafts?: {[path: string]: DraftInfo[]};
@@ -106,7 +102,6 @@
 
 const initialState: CommentState = {
   comments: undefined,
-  robotComments: undefined,
   drafts: undefined,
   portedComments: undefined,
   portedDrafts: undefined,
@@ -168,19 +163,6 @@
 }
 
 // Private but used in tests.
-export function setRobotComments(
-  state: CommentState,
-  robotComments?: {
-    [path: string]: RobotCommentInfo[];
-  }
-): CommentState {
-  if (deepEqual(robotComments, state.robotComments)) return state;
-  const nextState = {...state};
-  nextState.robotComments = addPath(robotComments) || {};
-  return nextState;
-}
-
-// Private but used in tests.
 export function setDrafts(
   state: CommentState,
   drafts?: {[path: string]: DraftInfo[]}
@@ -291,9 +273,7 @@
   public readonly commentsLoading$ = select(
     this.state$,
     commentState =>
-      commentState.comments === undefined ||
-      commentState.robotComments === undefined ||
-      commentState.drafts === undefined
+      commentState.comments === undefined || commentState.drafts === undefined
   );
 
   public readonly comments$ = select(
@@ -301,16 +281,6 @@
     commentState => commentState.comments
   );
 
-  public readonly robotComments$ = select(
-    this.state$,
-    commentState => commentState.robotComments
-  );
-
-  public readonly robotCommentCount$ = select(
-    this.robotComments$,
-    robotComments => Object.values(robotComments ?? {}).flat().length
-  );
-
   public readonly drafts$ = select(
     this.state$,
     commentState => commentState.drafts
@@ -416,7 +386,6 @@
     commentState =>
       new ChangeComments(
         commentState.comments,
-        commentState.robotComments,
         commentState.drafts,
         commentState.portedComments,
         commentState.portedDrafts
@@ -534,16 +503,13 @@
             if (!changeNum) return of([undefined, undefined, undefined]);
             return forkJoin([
               this.restApiService.getDiffComments(changeNum),
-              this.restApiService.getDiffRobotComments(changeNum),
               this.restApiService.getDiffDrafts(changeNum),
             ]);
           })
         )
-        .subscribe(([comments, robotComments, drafts]) => {
-          this.reportRobotCommentStats(robotComments);
+        .subscribe(([comments, drafts]) => {
           this.modifyState(s => {
             s = setComments(s, comments);
-            s = setRobotComments(s, robotComments);
             return setDrafts(s, drafts);
           });
         })
@@ -598,34 +564,6 @@
     this.setState(reducer({...this.getState()}));
   }
 
-  private reportRobotCommentStats(obj?: PathToRobotCommentsInfoMap) {
-    if (!obj) return;
-    const comments = Object.values(obj).flat();
-    if (comments.length === 0) return;
-    const ids = comments.map(c => c.robot_id);
-    const latestPatchset = comments.reduce(
-      (latestPs, comment) =>
-        Math.max(latestPs, (comment?.patch_set as number) ?? 0),
-      0
-    );
-    const commentsLatest = comments.filter(c => c.patch_set === latestPatchset);
-    const commentsFixes = comments
-      .map(c => c.fix_suggestions?.length ?? 0)
-      .filter(l => l > 0);
-    const details = {
-      firstId: ids[0],
-      ids: [...new Set(ids)],
-      count: comments.length,
-      countLatest: commentsLatest.length,
-      countFixes: commentsFixes.length,
-    };
-    this.reporting.reportInteraction(
-      Interaction.ROBOT_COMMENTS_STATS,
-      details,
-      {deduping: Deduping.EVENT_ONCE_PER_CHANGE}
-    );
-  }
-
   private reportCommentStats(
     obj?: {[path: string]: CommentInfo[]},
     latestPatchset?: PatchSetNumber
diff --git a/polygerrit-ui/app/models/comments/comments-model_test.ts b/polygerrit-ui/app/models/comments/comments-model_test.ts
index b3dbc08..3b516eb 100644
--- a/polygerrit-ui/app/models/comments/comments-model_test.ts
+++ b/polygerrit-ui/app/models/comments/comments-model_test.ts
@@ -39,7 +39,6 @@
     draft.id = '1' as UrlEncodedCommentId;
     const state = {
       comments: {},
-      robotComments: {},
       drafts: {
         [draft.path!]: [draft],
       },
@@ -50,7 +49,6 @@
     const output = deleteDraft(state, draft);
     assert.deepEqual(output, {
       comments: {},
-      robotComments: {},
       drafts: {
         'abc.txt': [],
       },
@@ -83,9 +81,6 @@
     const diffCommentsSpy = stubRestApi('getDiffComments').returns(
       Promise.resolve({'foo.c': [createComment()]})
     );
-    const diffRobotCommentsSpy = stubRestApi('getDiffRobotComments').returns(
-      Promise.resolve({})
-    );
     const diffDraftsSpy = stubRestApi('getDiffDrafts').returns(
       Promise.resolve({})
     );
@@ -106,7 +101,6 @@
     testResolver(changeModelToken).updateStateChange(createParsedChange());
 
     await waitUntilCalled(diffCommentsSpy, 'diffCommentsSpy');
-    await waitUntilCalled(diffRobotCommentsSpy, 'diffRobotCommentsSpy');
     await waitUntilCalled(diffDraftsSpy, 'diffDraftsSpy');
     await waitUntilCalled(portedCommentsSpy, 'portedCommentsSpy');
     await waitUntilCalled(portedDraftsSpy, 'portedDraftsSpy');
diff --git a/polygerrit-ui/app/models/config/config-model.ts b/polygerrit-ui/app/models/config/config-model.ts
index 1636ad4..61b3bec 100644
--- a/polygerrit-ui/app/models/config/config-model.ts
+++ b/polygerrit-ui/app/models/config/config-model.ts
@@ -57,9 +57,10 @@
     serverConfig => serverConfig?.change?.mergeability_computation_behavior
   );
 
-  public enableRobotComments$ = select(
+  public allowMarkdownBase64ImagesInComments$ = select(
     this.serverConfig$,
-    serverConfig => !!serverConfig?.change?.enable_robot_comments
+    serverConfig =>
+      !!serverConfig?.change?.allow_markdown_base64_images_in_comments
   );
 
   public docsBaseUrl$ = select(
diff --git a/polygerrit-ui/app/rollup.config.js b/polygerrit-ui/app/rollup.config.js
index 97139e0..05dc3fe 100644
--- a/polygerrit-ui/app/rollup.config.js
+++ b/polygerrit-ui/app/rollup.config.js
@@ -40,7 +40,7 @@
     name: 'import-meta-url-resolver',
     resolveImportMeta(property, data) {
       if (property === 'url' && data.moduleId.endsWith('/@polymer/font-roboto-local/roboto.js')) {
-        return 'new URL("..", document.baseURI).href';
+        return `window.location.origin + getBaseUrl() + '/'`;
       }
       return null;
     },
diff --git a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl.ts b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl.ts
index 4601bd2..21b6495 100644
--- a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl.ts
+++ b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl.ts
@@ -54,7 +54,6 @@
   EncodedGroupId,
   FileNameToFileInfoMap,
   FilePathToDiffInfoMap,
-  FixId,
   GitRef,
   GpgKeyId,
   GpgKeyInfo,
@@ -78,7 +77,6 @@
   Password,
   PatchRange,
   PatchSetNum,
-  PathToRobotCommentsInfoMap,
   PluginInfo,
   PreferencesInfo,
   PreferencesInput,
@@ -107,17 +105,14 @@
   ListChangesOption,
   ReviewResult,
   SubmitRequirementInfo,
+  SubmitRequirementInput,
 } from '../../types/common';
 import {
   DiffInfo,
   DiffPreferencesInfo,
   IgnoreWhitespaceType,
 } from '../../types/diff';
-import {
-  GetDiffCommentsOutput,
-  GetDiffRobotCommentsOutput,
-  RestApiService,
-} from './gr-rest-api';
+import {GetDiffCommentsOutput, RestApiService} from './gr-rest-api';
 import {
   CommentSide,
   createDefaultDiffPrefs,
@@ -135,7 +130,7 @@
 import {escapeAndWrapSearchOperatorValue} from '../../utils/string-util';
 import {FlagsService, KnownExperimentId} from '../flags/flags';
 import {RetryScheduler} from '../scheduler/retry-scheduler';
-import {FixReplacementInfo} from '../../api/rest-api';
+import {FileInfo, FixReplacementInfo} from '../../api/rest-api';
 import {
   FetchParams,
   FetchPromisesCache,
@@ -1333,6 +1328,31 @@
     );
   }
 
+  async getAllRevisionFiles(
+    changeNum?: NumericChangeId
+  ): Promise<
+    {[revisionId: string]: {[filename: string]: FileInfo}} | undefined
+  > {
+    if (!changeNum) return;
+    const optionsHex = listChangesOptionsToHex(
+      ListChangesOption.ALL_REVISIONS,
+      ListChangesOption.ALL_FILES
+    );
+
+    const change = await this.getChange(changeNum, undefined, optionsHex);
+    if (!change?.revisions) {
+      return undefined;
+    }
+    const result: {[revisionId: string]: {[filename: string]: FileInfo}} = {};
+    for (const revId in change.revisions) {
+      if (!change.revisions[revId]?.files) {
+        continue;
+      }
+      result[revId] = change.revisions[revId].files!;
+    }
+    return result;
+  }
+
   private getListChangesOptionsHex() {
     if (
       window.DEFAULT_DETAIL_HEXES &&
@@ -1785,6 +1805,59 @@
     }) as Promise<SubmitRequirementInfo[] | undefined>;
   }
 
+  createSubmitRequirement(
+    repoName: RepoName,
+    input: SubmitRequirementInput,
+    errFn?: ErrorCallback
+  ): Promise<SubmitRequirementInfo | undefined> {
+    return this._restApiHelper.fetchJSON({
+      url: `/projects/${encodeURIComponent(
+        repoName
+      )}/submit_requirements/${encodeURIComponent(input.name)}`,
+      fetchOptions: getFetchOptions({
+        method: HttpMethod.PUT,
+        body: input,
+      }),
+      errFn,
+      anonymizedUrl: '/projects/*/submit_requirements/*',
+    }) as Promise<SubmitRequirementInfo | undefined>;
+  }
+
+  updateSubmitRequirement(
+    repoName: RepoName,
+    submitRequirementName: string,
+    input: SubmitRequirementInput,
+    errFn?: ErrorCallback
+  ): Promise<SubmitRequirementInfo | undefined> {
+    return this._restApiHelper.fetchJSON({
+      url: `/projects/${encodeURIComponent(
+        repoName
+      )}/submit_requirements/${encodeURIComponent(submitRequirementName)}`,
+      fetchOptions: getFetchOptions({
+        method: HttpMethod.PUT,
+        body: input,
+      }),
+      errFn,
+      anonymizedUrl: '/projects/*/submit_requirements/*',
+    }) as Promise<SubmitRequirementInfo | undefined>;
+  }
+
+  deleteSubmitRequirement(
+    repoName: RepoName,
+    submitRequirementName: string,
+    errFn?: ErrorCallback
+  ): Promise<Response> {
+    return this._restApiHelper.fetch({
+      fetchOptions: {method: HttpMethod.DELETE},
+      url: `/projects/${encodeURIComponent(
+        repoName
+      )}/submit_requirements/${encodeURIComponent(submitRequirementName)}`,
+      errFn,
+      anonymizedUrl: '/projects/*/submit_requirements/*',
+      reportServerError: true,
+    });
+  }
+
   getRepoAccessRights(
     repoName: RepoName,
     errFn?: ErrorCallback
@@ -2401,19 +2474,6 @@
     }) as Promise<FilePathToDiffInfoMap | undefined>;
   }
 
-  async getRobotCommentFixPreview(
-    changeNum: NumericChangeId,
-    patchNum: PatchSetNum,
-    fixId: FixId
-  ): Promise<FilePathToDiffInfoMap | undefined> {
-    const url = await this._changeBaseURL(changeNum, patchNum);
-    const endpoint = `/fixes/${encodeURIComponent(fixId)}/preview`;
-    return this._restApiHelper.fetchJSON({
-      url: `${url}${endpoint}`,
-      anonymizedUrl: `${ANONYMIZED_REVISION_BASE_URL}${endpoint}`,
-    }) as Promise<FilePathToDiffInfoMap | undefined>;
-  }
-
   async applyFixSuggestion(
     changeNum: NumericChangeId,
     fixPatchNum: PatchSetNum,
@@ -2447,21 +2507,6 @@
     });
   }
 
-  async applyRobotFixSuggestion(
-    changeNum: NumericChangeId,
-    patchNum: PatchSetNum,
-    fixId: string
-  ): Promise<Response> {
-    const url = await this._changeBaseURL(changeNum, patchNum);
-    const endpoint = `/fixes/${encodeURIComponent(fixId)}/apply`;
-    return this._restApiHelper.fetch({
-      fetchOptions: {method: HttpMethod.POST},
-      url: `${url}${endpoint}`,
-      anonymizedUrl: `${ANONYMIZED_REVISION_BASE_URL}${endpoint}`,
-      reportServerError: true,
-    });
-  }
-
   async publishChangeEdit(changeNum: NumericChangeId) {
     const url = await this._changeBaseURL(changeNum);
     return this._restApiHelper.fetch({
@@ -2633,37 +2678,6 @@
     );
   }
 
-  getDiffRobotComments(
-    changeNum: NumericChangeId
-  ): Promise<PathToRobotCommentsInfoMap | undefined>;
-
-  getDiffRobotComments(
-    changeNum: NumericChangeId,
-    basePatchNum: BasePatchSetNum,
-    patchNum: PatchSetNum,
-    path: string
-  ): Promise<GetDiffRobotCommentsOutput>;
-
-  getDiffRobotComments(
-    changeNum: NumericChangeId,
-    basePatchNum?: BasePatchSetNum,
-    patchNum?: PatchSetNum,
-    path?: string
-  ) {
-    if (!basePatchNum && !patchNum && !path) {
-      return this._getDiffComments(changeNum, '/robotcomments');
-    }
-
-    return this._getDiffComments(
-      changeNum,
-      '/robotcomments',
-      undefined,
-      basePatchNum,
-      patchNum,
-      path
-    );
-  }
-
   async getDiffDrafts(
     changeNum: NumericChangeId
   ): Promise<{[path: string]: DraftInfo[]} | undefined> {
@@ -2707,11 +2721,6 @@
 
   _getDiffComments(
     changeNum: NumericChangeId,
-    endpoint: '/robotcomments'
-  ): Promise<PathToRobotCommentsInfoMap | undefined>;
-
-  _getDiffComments(
-    changeNum: NumericChangeId,
     endpoint: '/comments' | '/drafts',
     params?: FetchParams,
     basePatchNum?: BasePatchSetNum,
@@ -2719,15 +2728,6 @@
     path?: string
   ): Promise<GetDiffCommentsOutput>;
 
-  _getDiffComments(
-    changeNum: NumericChangeId,
-    endpoint: '/robotcomments',
-    params?: FetchParams,
-    basePatchNum?: BasePatchSetNum,
-    patchNum?: PatchSetNum,
-    path?: string
-  ): Promise<GetDiffRobotCommentsOutput>;
-
   /**
    * Fetches the comments for a given patchNum.
    * Helper function to make promises more legible.
@@ -2740,11 +2740,7 @@
     patchNum?: PatchSetNum,
     path?: string
   ): Promise<
-    | GetDiffCommentsOutput
-    | GetDiffRobotCommentsOutput
-    | {[path: string]: CommentInfo[]}
-    | PathToRobotCommentsInfoMap
-    | undefined
+    GetDiffCommentsOutput | {[path: string]: CommentInfo[]} | undefined
   > {
     // We don't want to add accept header, since preloading of comments is
     // working only without accept header.
@@ -2759,9 +2755,7 @@
           },
           noAcceptHeader
         )
-      ) as Promise<
-        {[path: string]: CommentInfo[]} | PathToRobotCommentsInfoMap | undefined
-      >;
+      ) as Promise<{[path: string]: CommentInfo[]} | undefined>;
 
     if (!basePatchNum && !patchNum && !path) {
       return fetchComments();
@@ -3329,7 +3323,7 @@
 
   getChange(
     changeNum: ChangeId | NumericChangeId,
-    errFn: ErrorCallback,
+    errFn?: ErrorCallback,
     optionsHex?: string
   ): Promise<ChangeInfo | undefined> {
     if (changeNum in this._projectLookup) {
diff --git a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl_test.ts b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl_test.ts
index bafb397..7a1ecfe 100644
--- a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl_test.ts
+++ b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api-impl_test.ts
@@ -50,7 +50,6 @@
   PatchSetNum,
   RepoName,
   RevisionPatchSetNum,
-  RobotCommentInfo,
   Timestamp,
   UrlEncodedCommentId,
 } from '../../types/common';
@@ -128,13 +127,13 @@
       message: 'how did this work in the first place?',
       path: 'sieve.go',
       updated: '2017-02-03 22:33:28.000000000' as Timestamp,
-    } as RobotCommentInfo);
+    } as CommentInfo);
     assert.equal(obj.comments.length, 1);
     assert.deepEqual(obj.comments[0], {
       message: 'this isn’t quite right',
       path: 'sieve.go',
       updated: '2017-02-03 22:32:28.000000000' as Timestamp,
-    } as RobotCommentInfo);
+    } as CommentInfo);
   });
 
   test('_setRange', () => {
@@ -296,18 +295,18 @@
       message: 'this isn’t quite right',
       path: 'sieve.go',
       updated: '2017-02-03 22:32:28.000000000' as Timestamp,
-    } as RobotCommentInfo);
+    } as CommentInfo);
     assert.equal(obj.comments.length, 2);
     assert.deepEqual(obj.comments[0], {
       message: 'What on earth are you thinking, here?',
       path: 'sieve.go',
       updated: '2017-02-03 22:32:28.000000000' as Timestamp,
-    } as RobotCommentInfo);
+    } as CommentInfo);
     assert.deepEqual(obj.comments[1], {
       message: '¯\\_(ツ)_/¯',
       path: 'sieve.go',
       updated: '2017-02-04 22:33:28.000000000' as Timestamp,
-    } as RobotCommentInfo);
+    } as CommentInfo);
   });
 
   test('legacy n,z key in change url is replaced', async () => {
@@ -627,9 +626,11 @@
       {username: 'john'}
     );
     assert.deepEqual(
-      (element._cache.get(
-        '/accounts/self/detail'
-      ) as unknown as AccountDetailInfo)!.username,
+      (
+        element._cache.get(
+          '/accounts/self/detail'
+        ) as unknown as AccountDetailInfo
+      ).username,
       'john'
     );
   });
@@ -649,9 +650,11 @@
       HttpMethod.PUT
     );
     assert.isUndefined(
-      (element._cache.get(
-        '/accounts/self/detail'
-      ) as unknown as AccountDetailInfo)!.username
+      (
+        element._cache.get(
+          '/accounts/self/detail'
+        ) as unknown as AccountDetailInfo
+      ).username
     );
   });
 
@@ -675,9 +678,11 @@
       {display_name: 'john'}
     );
     assert.deepEqual(
-      (element._cache.get(
-        '/accounts/self/detail'
-      ) as unknown as AccountDetailInfo)!.display_name,
+      (
+        element._cache.get(
+          '/accounts/self/detail'
+        ) as unknown as AccountDetailInfo
+      ).display_name,
       'john'
     );
   });
@@ -697,9 +702,11 @@
       HttpMethod.PUT
     );
     assert.isUndefined(
-      (element._cache.get(
-        '/accounts/self/detail'
-      ) as unknown as AccountDetailInfo)!.display_name
+      (
+        element._cache.get(
+          '/accounts/self/detail'
+        ) as unknown as AccountDetailInfo
+      ).display_name
     );
   });
 
@@ -723,9 +730,11 @@
       {name: 'john'}
     );
     assert.deepEqual(
-      (element._cache.get(
-        '/accounts/self/detail'
-      ) as unknown as AccountDetailInfo)!.name,
+      (
+        element._cache.get(
+          '/accounts/self/detail'
+        ) as unknown as AccountDetailInfo
+      ).name,
       'john'
     );
   });
@@ -745,9 +754,11 @@
       HttpMethod.PUT
     );
     assert.isUndefined(
-      (element._cache.get(
-        '/accounts/self/detail'
-      ) as unknown as AccountDetailInfo)!.name
+      (
+        element._cache.get(
+          '/accounts/self/detail'
+        ) as unknown as AccountDetailInfo
+      ).name
     );
   });
 
@@ -771,9 +782,11 @@
       {status: 'OOO'}
     );
     assert.deepEqual(
-      (element._cache.get(
-        '/accounts/self/detail'
-      ) as unknown as AccountDetailInfo)!.status,
+      (
+        element._cache.get(
+          '/accounts/self/detail'
+        ) as unknown as AccountDetailInfo
+      ).status,
       'OOO'
     );
   });
@@ -793,9 +806,11 @@
       HttpMethod.PUT
     );
     assert.isUndefined(
-      (element._cache.get(
-        '/accounts/self/detail'
-      ) as unknown as AccountDetailInfo)!.status
+      (
+        element._cache.get(
+          '/accounts/self/detail'
+        ) as unknown as AccountDetailInfo
+      ).status
     );
   });
 
@@ -1604,7 +1619,7 @@
     });
     assert.isTrue(fetchStub.calledOnce);
     assert.sameDeepMembers(
-      JSON.parse(fetchStub.lastCall.args[0].fetchOptions?.body as string).add!,
+      JSON.parse(fetchStub.lastCall.args[0].fetchOptions?.body as string).add,
       ['foo-bar']
     );
   });
diff --git a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
index ea6451a..4c0fb48 100644
--- a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
+++ b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
@@ -40,7 +40,6 @@
   EncodedGroupId,
   FileNameToFileInfoMap,
   FilePathToDiffInfoMap,
-  FixId,
   GitRef,
   GpgKeyId,
   GpgKeyInfo,
@@ -62,7 +61,6 @@
   Password,
   PatchRange,
   PatchSetNum,
-  PathToRobotCommentsInfoMap,
   PluginInfo,
   PreferencesInfo,
   PreferencesInput,
@@ -78,7 +76,6 @@
   RequestPayload,
   ReviewInput,
   RevisionId,
-  RobotCommentInfo,
   ServerInfo,
   ValidationOptionsInfo,
   SshKeyInfo,
@@ -92,6 +89,7 @@
   DraftInfo,
   ReviewResult,
   SubmitRequirementInfo,
+  SubmitRequirementInput,
 } from '../../types/common';
 import {
   DiffInfo,
@@ -100,18 +98,13 @@
 } from '../../types/diff';
 import {Finalizable, ParsedChangeInfo} from '../../types/types';
 import {ErrorCallback} from '../../api/rest';
-import {FixReplacementInfo} from '../../api/rest-api';
+import {FileInfo, FixReplacementInfo} from '../../api/rest-api';
 
 export interface GetDiffCommentsOutput {
   baseComments: CommentInfo[];
   comments: CommentInfo[];
 }
 
-export interface GetDiffRobotCommentsOutput {
-  baseComments: RobotCommentInfo[];
-  comments: RobotCommentInfo[];
-}
-
 export interface RestApiService extends Finalizable {
   getConfig(
     noCache?: boolean,
@@ -204,6 +197,16 @@
   ): Promise<ParsedChangeInfo | undefined>;
 
   /**
+   * For every revision of the change returns the list of FileInfo for files
+   * which are modified compared to revision's parent.
+   */
+  getAllRevisionFiles(
+    changeNum?: NumericChangeId
+  ): Promise<
+    {[revisionId: string]: {[filename: string]: FileInfo}} | undefined
+  >;
+
+  /**
    * Given a changeNum, gets the change.
    *
    * If the project is known for the specified changeNum uses
@@ -291,6 +294,25 @@
     errFn?: ErrorCallback
   ): Promise<SubmitRequirementInfo[] | undefined>;
 
+  createSubmitRequirement(
+    repoName: RepoName,
+    input: SubmitRequirementInput,
+    errFn?: ErrorCallback
+  ): Promise<SubmitRequirementInfo | undefined>;
+
+  updateSubmitRequirement(
+    repoName: RepoName,
+    submitRequirementName: string,
+    input: SubmitRequirementInput,
+    errFn?: ErrorCallback
+  ): Promise<SubmitRequirementInfo | undefined>;
+
+  deleteSubmitRequirement(
+    repoName: RepoName,
+    submitRequirementName: string,
+    errFn?: ErrorCallback
+  ): Promise<Response>;
+
   getRepoAccessRights(
     repoName: RepoName,
     errFn?: ErrorCallback
@@ -449,24 +471,6 @@
     | Promise<{[path: string]: CommentInfo[]} | undefined>
     | Promise<GetDiffCommentsOutput>;
 
-  getDiffRobotComments(
-    changeNum: NumericChangeId
-  ): Promise<PathToRobotCommentsInfoMap | undefined>;
-  getDiffRobotComments(
-    changeNum: NumericChangeId,
-    basePatchNum: PatchSetNum,
-    patchNum: PatchSetNum,
-    path: string
-  ): Promise<GetDiffRobotCommentsOutput>;
-  getDiffRobotComments(
-    changeNum: NumericChangeId,
-    basePatchNum?: BasePatchSetNum,
-    patchNum?: PatchSetNum,
-    path?: string
-  ):
-    | Promise<GetDiffRobotCommentsOutput>
-    | Promise<PathToRobotCommentsInfoMap | undefined>;
-
   /**
    * If the user is logged in, fetch the user's draft diff comments. If there
    * is no logged in user, the request is not made and the promise yields an
@@ -707,17 +711,6 @@
   awaitPendingDiffDrafts(): Promise<void>;
 
   /**
-   * Preview Stored Fix
-   * Gets the diffs of all files for a certain {fix-id} associated with apply fix.
-   * https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#preview-stored-fix
-   */
-  getRobotCommentFixPreview(
-    changeNum: NumericChangeId,
-    patchNum: PatchSetNum,
-    fixId: FixId
-  ): Promise<FilePathToDiffInfoMap | undefined>;
-
-  /**
    * Preview Provided fix
    * Gets the diffs of all files for a provided fix replacements infos
    * https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#preview-provided-fix
@@ -741,16 +734,6 @@
   ): Promise<Response>;
 
   /**
-   * Apply Stored Fix
-   * https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#apply-stored-fix
-   */
-  applyRobotFixSuggestion(
-    changeNum: NumericChangeId,
-    patchNum: PatchSetNum,
-    fixId: string
-  ): Promise<Response>;
-
-  /**
    * @param basePatchNum Negative values specify merge parent
    * index.
    * @param whitespace the ignore-whitespace level for the diff
diff --git a/polygerrit-ui/app/services/service-worker-installer.ts b/polygerrit-ui/app/services/service-worker-installer.ts
index 2bede59..a4d0732 100644
--- a/polygerrit-ui/app/services/service-worker-installer.ts
+++ b/polygerrit-ui/app/services/service-worker-installer.ts
@@ -46,12 +46,12 @@
 }
 
 export class ServiceWorkerInstaller extends Model<ServiceWorkerInstallerState> {
-  readonly initialized$: Observable<Boolean | undefined> = select(
+  readonly initialized$: Observable<boolean | undefined> = select(
     this.state$,
     state => state.initialized
   );
 
-  readonly shouldShowPrompt$: Observable<Boolean | undefined> = select(
+  readonly shouldShowPrompt$: Observable<boolean | undefined> = select(
     this.initialized$,
     _ => this.shouldShowPrompt()
   );
diff --git a/polygerrit-ui/app/styles/themes/app-theme.ts b/polygerrit-ui/app/styles/themes/app-theme.ts
index 97993c1..8f69e26 100644
--- a/polygerrit-ui/app/styles/themes/app-theme.ts
+++ b/polygerrit-ui/app/styles/themes/app-theme.ts
@@ -313,7 +313,6 @@
 
     /* comment background colors */
     --comment-background-color: var(--gray-200);
-    --robot-comment-background-color: var(--blue-50);
     --unresolved-comment-background-color: #fef7e0;
 
 
diff --git a/polygerrit-ui/app/styles/themes/dark-theme.ts b/polygerrit-ui/app/styles/themes/dark-theme.ts
index 635d246..ee43f15 100644
--- a/polygerrit-ui/app/styles/themes/dark-theme.ts
+++ b/polygerrit-ui/app/styles/themes/dark-theme.ts
@@ -136,7 +136,6 @@
 
     /* comment background colors */
     --comment-background-color: #3c3f43;
-    --robot-comment-background-color: #1e3a5f;
     --unresolved-comment-background-color: #614a19;
 
     /* Suggest edits */
diff --git a/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts b/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts
index 95f160d..552dfeb 100644
--- a/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts
+++ b/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts
@@ -96,9 +96,6 @@
   applyFixSuggestion(): Promise<Response> {
     return Promise.resolve(new Response());
   },
-  applyRobotFixSuggestion(): Promise<Response> {
-    return Promise.resolve(new Response());
-  },
   awaitPendingDiffDrafts(): Promise<void> {
     return Promise.resolve();
   },
@@ -206,6 +203,9 @@
   getAccountStatus(): Promise<string | undefined> {
     return Promise.resolve('');
   },
+  getAllRevisionFiles() {
+    return Promise.resolve(undefined);
+  },
   getAvatarChangeUrl(): Promise<string | undefined> {
     return Promise.resolve('');
   },
@@ -315,11 +315,6 @@
   getDiffPreferences(): Promise<DiffPreferencesInfo | undefined> {
     return Promise.resolve(createDefaultDiffPrefs());
   },
-  getDiffRobotComments() {
-    // NOTE: This method can not be typed properly due to overloads.
-    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-    return Promise.resolve({}) as any;
-  },
   getDocumentationSearches(): Promise<DocResult[] | undefined> {
     return Promise.resolve([]);
   },
@@ -397,6 +392,15 @@
   getRepoSubmitRequirements(): Promise<SubmitRequirementInfo[] | undefined> {
     return Promise.resolve([]);
   },
+  createSubmitRequirement(): Promise<SubmitRequirementInfo | undefined> {
+    return Promise.resolve(undefined);
+  },
+  updateSubmitRequirement(): Promise<SubmitRequirementInfo | undefined> {
+    return Promise.resolve(undefined);
+  },
+  deleteSubmitRequirement(): Promise<Response> {
+    return Promise.resolve(new Response());
+  },
   getRepoAccessRights(): Promise<ProjectAccessInfo | undefined> {
     return Promise.resolve(undefined);
   },
@@ -418,9 +422,6 @@
   getFixPreview(): Promise<FilePathToDiffInfoMap | undefined> {
     return Promise.resolve({});
   },
-  getRobotCommentFixPreview(): Promise<FilePathToDiffInfoMap | undefined> {
-    return Promise.resolve({});
-  },
   queryAccounts(): Promise<AccountInfo[] | undefined> {
     return Promise.resolve([]);
   },
diff --git a/polygerrit-ui/app/test/test-data-generators.ts b/polygerrit-ui/app/test/test-data-generators.ts
index 5f40cad..2fa7368 100644
--- a/polygerrit-ui/app/test/test-data-generators.ts
+++ b/polygerrit-ui/app/test/test-data-generators.ts
@@ -57,9 +57,6 @@
   Reviewers,
   RevisionInfo,
   RevisionPatchSetNum,
-  RobotCommentInfo,
-  RobotId,
-  RobotRunId,
   SchemesInfoMap,
   ServerInfo,
   SubmittedTogetherInfo,
@@ -906,36 +903,6 @@
   };
 }
 
-export function createRobotComment(
-  extra: Partial<CommentInfo> = {}
-): RobotCommentInfo {
-  return {
-    ...createComment(),
-    robot_id: 'robot-id-123' as RobotId,
-    robot_run_id: 'robot-run-id-456' as RobotRunId,
-    properties: {},
-    fix_suggestions: [
-      {
-        fix_id: 'robot-run-id-456-fix' as FixId,
-        description: 'Robot suggestion',
-        replacements: [
-          {
-            path: 'abc.txt'!,
-            range: {
-              start_line: 0,
-              start_character: 0,
-              end_line: 1,
-              end_character: 10,
-            },
-            replacement: 'replacement',
-          },
-        ],
-      },
-    ],
-    ...extra,
-  };
-}
-
 export function createChangeComments(): ChangeComments {
   const comments = {
     '/COMMIT_MSG': [
@@ -1036,7 +1003,7 @@
       },
     ],
   };
-  return new ChangeComments(comments, {}, drafts, {}, {});
+  return new ChangeComments(comments, drafts, {}, {});
 }
 
 export function createThread(
diff --git a/polygerrit-ui/app/types/common.ts b/polygerrit-ui/app/types/common.ts
index 47669f4..32b2465 100644
--- a/polygerrit-ui/app/types/common.ts
+++ b/polygerrit-ui/app/types/common.ts
@@ -238,10 +238,6 @@
  */
 export type ParsedJSON = BrandType<unknown, '_parsedJSON'>;
 
-export type RobotId = BrandType<string, '_robotId'>;
-
-export type RobotRunId = BrandType<string, '_robotRunId'>;
-
 // RevisionId '0' is the same as 'current'. However, we want to avoid '0'
 // in our code, so it is not added here as a possible value.
 export type RevisionId = 'current' | CommitId | PatchSetNum;
@@ -592,22 +588,16 @@
 }
 
 /**
- * This is what human, robot and draft comments can agree upon.
+ * This is what published and draft comments can agree upon.
  *
  * Note that `id` and `updated` must be considered optional, because we might
  * be dealing with unsaved draft comments.
  */
-export type Comment = DraftInfo | CommentInfo | RobotCommentInfo;
+export type Comment = DraftInfo | CommentInfo;
 
 // TODO: Replace the CommentMap type with just an array of paths.
 export type CommentMap = {[path: string]: boolean};
 
-export function isRobot<T extends Comment>(
-  x: T | RobotCommentInfo | undefined
-): x is RobotCommentInfo {
-  return !!x && !!(x as RobotCommentInfo).robot_id;
-}
-
 export function isDraft<T extends Comment>(
   x: T | DraftInfo | undefined
 ): x is DraftInfo {
@@ -740,6 +730,19 @@
 }
 
 /**
+ * The SubmitRequirementInput entity describes a submit requirement input.
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#submit-requirement-input
+ */
+export interface SubmitRequirementInput {
+  name: string;
+  description?: string;
+  applicability_expression?: string;
+  submittability_expression: string;
+  override_expression?: string;
+  allow_override_in_child_projects?: boolean;
+}
+
+/**
  * The ProjectAccessInfo entity contains information about the access rights for
  * a project.
  * https://gerrit-review.googlesource.com/Documentation/rest-api-access.html#project-access-info
@@ -1126,7 +1129,6 @@
   tag?: ReviewInputTag;
   labels?: LabelNameToValueMap;
   comments?: PathToCommentsInputMap;
-  robot_comments?: PathToRobotCommentsMap;
   drafts?: DraftsAction;
   notify?: NotifyType;
   notify_details?: RecipientTypeToNotifyInfoMap;
@@ -1169,30 +1171,11 @@
 
 export type LabelNameToValueMap = {[labelName: string]: number};
 export type PathToCommentsInputMap = {[path: string]: CommentInput[]};
-export type PathToRobotCommentsMap = {[path: string]: RobotCommentInput[]};
 export type RecipientTypeToNotifyInfoMap = {
   [recepientType: string]: NotifyInfo;
 };
 
 /**
- * The RobotCommentInput entity contains information for creating an inline robot comment
- * https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#robot-comment-input
- */
-export type RobotCommentInput = RobotCommentInfo;
-
-/**
- * The RobotCommentInfo entity contains information about a robot inline comment
- * https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#robot-comment-info
- */
-export interface RobotCommentInfo extends CommentInfo {
-  robot_id: RobotId;
-  robot_run_id: RobotRunId;
-  url?: string;
-  properties: {[propertyName: string]: string};
-}
-export type PathToRobotCommentsInfoMap = {[path: string]: RobotCommentInfo[]};
-
-/**
  * The ApplyProvidedFixInput entity contains information for applying fixes, provided in the
  * request body, to a revision.
  * https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#apply-provided-fix
diff --git a/polygerrit-ui/app/utils/comment-util.ts b/polygerrit-ui/app/utils/comment-util.ts
index ecc3c99..36dc12e 100644
--- a/polygerrit-ui/app/utils/comment-util.ts
+++ b/polygerrit-ui/app/utils/comment-util.ts
@@ -21,7 +21,6 @@
   CommentThread,
   DraftInfo,
   ChangeMessage,
-  isRobot,
   isDraft,
   Comment,
   CommentIdToCommentThreadMap,
@@ -337,10 +336,6 @@
     .includes(account.email);
 }
 
-export function isRobotThread(thread: CommentThread): boolean {
-  return isRobot(getFirstComment(thread));
-}
-
 export function hasSuggestion(thread: CommentThread): boolean {
   const firstComment = getFirstComment(thread);
   if (!firstComment) return false;
@@ -350,10 +345,6 @@
   );
 }
 
-export function hasHumanReply(thread: CommentThread): boolean {
-  return countComments(thread) > 1 && !isRobot(getLastComment(thread));
-}
-
 export function lastUpdated(thread: CommentThread): Date | undefined {
   // We don't want to re-sort comments when you save a draft reply, so
   // we stick to the timestampe of the last *published* comment.
@@ -557,9 +548,7 @@
 
 // This can either mean a user or a checks provided fix.
 // "Provided" means that the fix is sent along with the request
-// when previewing and applying the fix. This is in contrast to
-// robot comment fixes, which are stored in the backend, and they
-// are referenced by a unique `FixId`;
+// when previewing and applying the fix.
 export const PROVIDED_FIX_ID = 'provided_fix' as FixId;
 
 export function hasUserSuggestion(comment: Comment) {
diff --git a/polygerrit-ui/app/utils/label-util.ts b/polygerrit-ui/app/utils/label-util.ts
index e34e96b..dd1c894 100644
--- a/polygerrit-ui/app/utils/label-util.ts
+++ b/polygerrit-ui/app/utils/label-util.ts
@@ -362,6 +362,16 @@
   return priorityRequirementList.concat(nonPriorityRequirements);
 }
 
+export function orderSubmitRequirementNames(names: string[]) {
+  const result = PRIORITY_REQUIREMENTS_ORDER.filter(label =>
+    names.includes(label)
+  );
+  const nonPriorityRequirements = names
+    .filter(name => !PRIORITY_REQUIREMENTS_ORDER.includes(name))
+    .sort();
+  return result.concat(nonPriorityRequirements);
+}
+
 function getStringLabelValue(
   labels: LabelNameToInfoMap,
   labelName: string,
diff --git a/polygerrit-ui/app/utils/label-util_test.ts b/polygerrit-ui/app/utils/label-util_test.ts
index a0b6c50..4e29079 100644
--- a/polygerrit-ui/app/utils/label-util_test.ts
+++ b/polygerrit-ui/app/utils/label-util_test.ts
@@ -27,6 +27,8 @@
   hasVotes,
   hasVoted,
   extractLabelsWithCountFrom,
+  orderSubmitRequirements,
+  StandardLabels,
 } from './label-util';
 import {
   AccountId,
@@ -901,4 +903,57 @@
       assert.isTrue(hasVoted(quickLabelInfo, account));
     });
   });
+
+  suite('orderSubmitRequirements', () => {
+    test('orders priority requirements first', () => {
+      const codeReview = {
+        ...createSubmitRequirementResultInfo(),
+        name: StandardLabels.CODE_REVIEW,
+      };
+      const codeOwners = {
+        ...createSubmitRequirementResultInfo(),
+        name: StandardLabels.CODE_OWNERS,
+      };
+      const presubmitVerified = {
+        ...createSubmitRequirementResultInfo(),
+        name: StandardLabels.PRESUBMIT_VERIFIED,
+      };
+      const customLabel = createSubmitRequirementResultInfo('Custom-Label');
+
+      const requirements = [
+        customLabel,
+        codeReview,
+        presubmitVerified,
+        codeOwners,
+      ];
+      const ordered = orderSubmitRequirements(requirements);
+
+      assert.deepEqual(ordered, [
+        codeReview,
+        codeOwners,
+        presubmitVerified,
+        customLabel,
+      ]);
+    });
+
+    test('preserves order of non-priority requirements', () => {
+      const customLabel1 = {
+        ...createSubmitRequirementResultInfo(),
+        name: 'Custom-Label-1',
+      };
+      const customLabel2 = {
+        ...createSubmitRequirementResultInfo(),
+        name: 'Custom-Label-2',
+      };
+      const customLabel3 = {
+        ...createSubmitRequirementResultInfo(),
+        name: 'Custom-Label-3',
+      };
+
+      const requirements = [customLabel2, customLabel1, customLabel3];
+      const ordered = orderSubmitRequirements(requirements);
+
+      assert.deepEqual(ordered, requirements);
+    });
+  });
 });
diff --git a/polygerrit-ui/app/utils/string-util.ts b/polygerrit-ui/app/utils/string-util.ts
index abc5529..41ca9d1 100644
--- a/polygerrit-ui/app/utils/string-util.ts
+++ b/polygerrit-ui/app/utils/string-util.ts
@@ -56,6 +56,15 @@
   return str.charAt(0).toUpperCase() + str.slice(1);
 }
 
+export function trimWithEllipsis(
+  s: string | undefined,
+  maxLength: number
+): string {
+  if (!s) return '';
+  if (s.length <= maxLength) return s;
+  return s.substring(0, maxLength - 3) + '...';
+}
+
 /**
  * Converts the items into a sentence-friendly format. Examples:
  * listForSentence(["Foo", "Bar", "Baz"])
diff --git a/polygerrit-ui/app/utils/string-util_test.ts b/polygerrit-ui/app/utils/string-util_test.ts
index d6c4187..6ba3354 100644
--- a/polygerrit-ui/app/utils/string-util_test.ts
+++ b/polygerrit-ui/app/utils/string-util_test.ts
@@ -11,6 +11,7 @@
   listForSentence,
   diffFilePaths,
   escapeAndWrapSearchOperatorValue,
+  trimWithEllipsis,
 } from './string-util';
 
 suite('string-util tests', () => {
@@ -42,6 +43,14 @@
     assert.equal(listForSentence([]), '');
   });
 
+  test('trimWithEllipsis', () => {
+    assert.equal(trimWithEllipsis('asdf', 10), 'asdf');
+    assert.equal(trimWithEllipsis('asdf', 4), 'asdf');
+    assert.equal(trimWithEllipsis('asdf', 3), '...');
+    assert.equal(trimWithEllipsis('asdf qwer', 5), 'as...');
+    assert.equal(trimWithEllipsis('asdf qwer', 8), 'asdf ...');
+  });
+
   test('diffFilePaths', () => {
     const path = 'some/new/path/to/foo.js';
 
diff --git a/proto/cache.proto b/proto/cache.proto
index cfdbd4e..4717f1d 100644
--- a/proto/cache.proto
+++ b/proto/cache.proto
@@ -715,7 +715,7 @@
 
 // Serialized form of
 // com.google.gerrit.server.patch.filediff.FileDiffOutput
-// Next ID: 15
+// Next ID: 17
 message FileDiffOutputProto {
   // Next ID: 5
   message Edit {
@@ -749,4 +749,6 @@
   bool negative = 12;
   string old_mode = 13; // ENUM as string
   string new_mode = 14; // ENUM as string
+  bytes old_sha = 15;
+  bytes new_sha = 16;
 }
diff --git a/tools/js/eslint.bzl b/tools/js/eslint.bzl
index 320f8da..7dc73bb 100644
--- a/tools/js/eslint.bzl
+++ b/tools/js/eslint.bzl
@@ -41,6 +41,7 @@
             "@npm//eslint-plugin-import",
             "@npm//eslint-plugin-jsdoc",
             "@npm//eslint-plugin-lit",
+            "@npm//eslint-plugin-n",
             "@npm//eslint-plugin-prettier",
             "@npm//eslint-plugin-regex",
             "@npm//gts",
@@ -122,6 +123,11 @@
             "*_test_loader.js",
             "./",  # Relative to the config file location
         ],
+        # Needed for eslint 9+.
+        # Remove this when migrating the config to flat config.
+        env = {
+            "ESLINT_USE_FLAT_CONFIG": "false",
+        },
         # Should not run sandboxed.
         tags = [
             "local",
@@ -143,4 +149,7 @@
             "--ignore-pattern",
             "*_bin_loader.js",
         ],
+        env = {
+            "ESLINT_USE_FLAT_CONFIG": "false",
+        },
     )
diff --git a/yarn.lock b/yarn.lock
index 9a3b4a2..76a3c08 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,42 +2,24 @@
 # yarn lockfile v1
 
 
-"@75lb/deep-merge@^1.1.1":
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/@75lb/deep-merge/-/deep-merge-1.1.1.tgz#3b06155b90d34f5f8cc2107d796f1853ba02fd6d"
-  integrity sha512-xvgv6pkMGBA6GwdyJbNAnDmfAIR/DfWhrj9jgWh3TY7gRm3KO46x/GPjRg6wJ0nOepwqrNxFfojebh0Df4h4Tw==
-  dependencies:
-    lodash.assignwith "^4.2.0"
-    typical "^7.1.1"
-
 "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.11":
-  version "7.23.5"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244"
-  integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==
+  version "7.27.1"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
+  integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==
   dependencies:
-    "@babel/highlight" "^7.23.4"
-    chalk "^2.4.2"
-
-"@babel/helper-validator-identifier@^7.22.20":
-  version "7.22.20"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
-  integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
-
-"@babel/highlight@^7.23.4":
-  version "7.23.4"
-  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b"
-  integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.22.20"
-    chalk "^2.4.2"
+    "@babel/helper-validator-identifier" "^7.27.1"
     js-tokens "^4.0.0"
+    picocolors "^1.1.1"
+
+"@babel/helper-validator-identifier@^7.27.1":
+  version "7.27.1"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8"
+  integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
 
 "@babel/runtime@^7.10.2":
-  version "7.23.7"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.7.tgz#dd7c88deeb218a0f8bd34d5db1aa242e0f203193"
-  integrity sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA==
-  dependencies:
-    regenerator-runtime "^0.14.0"
+  version "7.27.1"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.1.tgz#9fce313d12c9a77507f264de74626e87fd0dc541"
+  integrity sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==
 
 "@bazel/concatjs@^5.8.1":
   version "5.8.1"
@@ -77,124 +59,149 @@
   dependencies:
     google-protobuf "^3.6.1"
 
-"@es-joy/jsdoccomment@~0.39.4":
-  version "0.39.4"
-  resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz#6b8a62e9b3077027837728818d3c4389a898b392"
-  integrity sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==
+"@es-joy/jsdoccomment@~0.50.1":
+  version "0.50.1"
+  resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.50.1.tgz#2f49d233b61a858349eff6dc803bbb28919fa700"
+  integrity sha512-fas3qe1hw38JJgU/0m5sDpcrbZGysBeZcMwW5Ws9brYxY64MJyWLXRZCj18keTycT1LFTrFXdSNMS+GRVaU6Hw==
   dependencies:
-    comment-parser "1.3.1"
-    esquery "^1.5.0"
-    jsdoc-type-pratt-parser "~4.0.0"
+    "@types/eslint" "^9.6.1"
+    "@types/estree" "^1.0.6"
+    "@typescript-eslint/types" "^8.11.0"
+    comment-parser "1.4.1"
+    esquery "^1.6.0"
+    jsdoc-type-pratt-parser "~4.1.0"
 
-"@esbuild/android-arm64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
-  integrity sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==
+"@esbuild/aix-ppc64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz#830d6476cbbca0c005136af07303646b419f1162"
+  integrity sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==
 
-"@esbuild/android-arm@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.19.tgz#5898f7832c2298bc7d0ab53701c57beb74d78b4d"
-  integrity sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==
+"@esbuild/android-arm64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz#d11d4fc299224e729e2190cacadbcc00e7a9fd67"
+  integrity sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==
 
-"@esbuild/android-x64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.19.tgz#658368ef92067866d95fb268719f98f363d13ae1"
-  integrity sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==
+"@esbuild/android-arm@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.4.tgz#5660bd25080553dd2a28438f2a401a29959bd9b1"
+  integrity sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==
 
-"@esbuild/darwin-arm64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz#584c34c5991b95d4d48d333300b1a4e2ff7be276"
-  integrity sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==
+"@esbuild/android-x64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.4.tgz#18ddde705bf984e8cd9efec54e199ac18bc7bee1"
+  integrity sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==
 
-"@esbuild/darwin-x64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz#7751d236dfe6ce136cce343dce69f52d76b7f6cb"
-  integrity sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==
+"@esbuild/darwin-arm64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz#b0b7fb55db8fc6f5de5a0207ae986eb9c4766e67"
+  integrity sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==
 
-"@esbuild/freebsd-arm64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz#cacd171665dd1d500f45c167d50c6b7e539d5fd2"
-  integrity sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==
+"@esbuild/darwin-x64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz#e6813fdeba0bba356cb350a4b80543fbe66bf26f"
+  integrity sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==
 
-"@esbuild/freebsd-x64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz#0769456eee2a08b8d925d7c00b79e861cb3162e4"
-  integrity sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==
+"@esbuild/freebsd-arm64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz#dc11a73d3ccdc308567b908b43c6698e850759be"
+  integrity sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==
 
-"@esbuild/linux-arm64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz#38e162ecb723862c6be1c27d6389f48960b68edb"
-  integrity sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==
+"@esbuild/freebsd-x64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz#91da08db8bd1bff5f31924c57a81dab26e93a143"
+  integrity sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==
 
-"@esbuild/linux-arm@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz#1a2cd399c50040184a805174a6d89097d9d1559a"
-  integrity sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==
+"@esbuild/linux-arm64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz#efc15e45c945a082708f9a9f73bfa8d4db49728a"
+  integrity sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==
 
-"@esbuild/linux-ia32@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz#e28c25266b036ce1cabca3c30155222841dc035a"
-  integrity sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==
+"@esbuild/linux-arm@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz#9b93c3e54ac49a2ede6f906e705d5d906f6db9e8"
+  integrity sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==
 
-"@esbuild/linux-loong64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz#0f887b8bb3f90658d1a0117283e55dbd4c9dcf72"
-  integrity sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==
+"@esbuild/linux-ia32@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz#be8ef2c3e1d99fca2d25c416b297d00360623596"
+  integrity sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==
 
-"@esbuild/linux-mips64el@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz#f5d2a0b8047ea9a5d9f592a178ea054053a70289"
-  integrity sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==
+"@esbuild/linux-loong64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz#b0840a2707c3fc02eec288d3f9defa3827cd7a87"
+  integrity sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==
 
-"@esbuild/linux-ppc64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz#876590e3acbd9fa7f57a2c7d86f83717dbbac8c7"
-  integrity sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==
+"@esbuild/linux-mips64el@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz#2a198e5a458c9f0e75881a4e63d26ba0cf9df39f"
+  integrity sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==
 
-"@esbuild/linux-riscv64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz#7f49373df463cd9f41dc34f9b2262d771688bf09"
-  integrity sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==
+"@esbuild/linux-ppc64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz#64f4ae0b923d7dd72fb860b9b22edb42007cf8f5"
+  integrity sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==
 
-"@esbuild/linux-s390x@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz#e2afd1afcaf63afe2c7d9ceacd28ec57c77f8829"
-  integrity sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==
+"@esbuild/linux-riscv64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz#fb2844b11fdddd39e29d291c7cf80f99b0d5158d"
+  integrity sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==
 
-"@esbuild/linux-x64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4"
-  integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==
+"@esbuild/linux-s390x@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz#1466876e0aa3560c7673e63fdebc8278707bc750"
+  integrity sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==
 
-"@esbuild/netbsd-x64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz#c29fb2453c6b7ddef9a35e2c18b37bda1ae5c462"
-  integrity sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==
+"@esbuild/linux-x64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz#c10fde899455db7cba5f11b3bccfa0e41bf4d0cd"
+  integrity sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==
 
-"@esbuild/openbsd-x64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz#95e75a391403cb10297280d524d66ce04c920691"
-  integrity sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==
+"@esbuild/netbsd-arm64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz#02e483fbcbe3f18f0b02612a941b77be76c111a4"
+  integrity sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==
 
-"@esbuild/sunos-x64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz#722eaf057b83c2575937d3ffe5aeb16540da7273"
-  integrity sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==
+"@esbuild/netbsd-x64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz#ec401fb0b1ed0ac01d978564c5fc8634ed1dc2ed"
+  integrity sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==
 
-"@esbuild/win32-arm64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz#9aa9dc074399288bdcdd283443e9aeb6b9552b6f"
-  integrity sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==
+"@esbuild/openbsd-arm64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz#f272c2f41cfea1d91b93d487a51b5c5ca7a8c8c4"
+  integrity sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==
 
-"@esbuild/win32-ia32@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz#95ad43c62ad62485e210f6299c7b2571e48d2b03"
-  integrity sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==
+"@esbuild/openbsd-x64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz#2e25950bc10fa9db1e5c868e3d50c44f7c150fd7"
+  integrity sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==
 
-"@esbuild/win32-x64@0.17.19":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061"
-  integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==
+"@esbuild/sunos-x64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz#cd596fa65a67b3b7adc5ecd52d9f5733832e1abd"
+  integrity sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==
+
+"@esbuild/win32-arm64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz#b4dbcb57b21eeaf8331e424c3999b89d8951dc88"
+  integrity sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==
+
+"@esbuild/win32-ia32@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz#410842e5d66d4ece1757634e297a87635eb82f7a"
+  integrity sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==
+
+"@esbuild/win32-x64@0.25.4":
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz#0b17ec8a70b2385827d52314c1253160a0b9bacc"
+  integrity sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==
+
+"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.5.0", "@eslint-community/eslint-utils@^4.7.0":
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a"
+  integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==
+  dependencies:
+    eslint-visitor-keys "^3.4.3"
 
 "@eslint-community/eslint-utils@^4.2.0":
   version "4.4.1"
@@ -203,54 +210,92 @@
   dependencies:
     eslint-visitor-keys "^3.4.3"
 
-"@eslint-community/regexpp@^4.4.0":
-  version "4.10.0"
-  resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63"
-  integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==
-
-"@eslint-community/regexpp@^4.6.1":
+"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0", "@eslint-community/regexpp@^4.12.1":
   version "4.12.1"
   resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
   integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
 
-"@eslint/eslintrc@^2.1.4":
-  version "2.1.4"
-  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad"
-  integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
+"@eslint/config-array@^0.20.0":
+  version "0.20.0"
+  resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.20.0.tgz#7a1232e82376712d3340012a2f561a2764d1988f"
+  integrity sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==
+  dependencies:
+    "@eslint/object-schema" "^2.1.6"
+    debug "^4.3.1"
+    minimatch "^3.1.2"
+
+"@eslint/config-helpers@^0.2.1":
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.2.2.tgz#3779f76b894de3a8ec4763b79660e6d54d5b1010"
+  integrity sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==
+
+"@eslint/core@^0.13.0":
+  version "0.13.0"
+  resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.13.0.tgz#bf02f209846d3bf996f9e8009db62df2739b458c"
+  integrity sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==
+  dependencies:
+    "@types/json-schema" "^7.0.15"
+
+"@eslint/eslintrc@^3.3.1":
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz#e55f7f1dd400600dd066dbba349c4c0bac916964"
+  integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==
   dependencies:
     ajv "^6.12.4"
     debug "^4.3.2"
-    espree "^9.6.0"
-    globals "^13.19.0"
+    espree "^10.0.1"
+    globals "^14.0.0"
     ignore "^5.2.0"
     import-fresh "^3.2.1"
     js-yaml "^4.1.0"
     minimatch "^3.1.2"
     strip-json-comments "^3.1.1"
 
-"@eslint/js@8.57.1":
-  version "8.57.1"
-  resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2"
-  integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
+"@eslint/js@9.26.0":
+  version "9.26.0"
+  resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.26.0.tgz#1e13126b67a3db15111d2dcc61f69a2acff70bd5"
+  integrity sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==
 
-"@humanwhocodes/config-array@^0.13.0":
-  version "0.13.0"
-  resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748"
-  integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==
+"@eslint/object-schema@^2.1.6":
+  version "2.1.6"
+  resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f"
+  integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==
+
+"@eslint/plugin-kit@^0.2.8":
+  version "0.2.8"
+  resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz#47488d8f8171b5d4613e833313f3ce708e3525f8"
+  integrity sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==
   dependencies:
-    "@humanwhocodes/object-schema" "^2.0.3"
-    debug "^4.3.1"
-    minimatch "^3.0.5"
+    "@eslint/core" "^0.13.0"
+    levn "^0.4.1"
+
+"@humanfs/core@^0.19.1":
+  version "0.19.1"
+  resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
+  integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==
+
+"@humanfs/node@^0.16.6":
+  version "0.16.6"
+  resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e"
+  integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==
+  dependencies:
+    "@humanfs/core" "^0.19.1"
+    "@humanwhocodes/retry" "^0.3.0"
 
 "@humanwhocodes/module-importer@^1.0.1":
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
   integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
 
-"@humanwhocodes/object-schema@^2.0.3":
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
-  integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
+"@humanwhocodes/retry@^0.3.0":
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
+  integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
+
+"@humanwhocodes/retry@^0.4.2":
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.2.tgz#1860473de7dfa1546767448f333db80cb0ff2161"
+  integrity sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==
 
 "@jridgewell/gen-mapping@^0.3.5":
   version "0.3.8"
@@ -304,6 +349,22 @@
   resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-4.2.1.tgz#1fead437f3957ceebe2e8c3f46beccdb9bc575b8"
   integrity sha512-EWUguj2kd7ldmrF9F+vI5hUOralPd+sdsUnYbRy33vZTuZkduC1shE9TtEMEjAQwyfyMb4ole5KtjF8MsnQOlA==
 
+"@modelcontextprotocol/sdk@^1.8.0":
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.11.0.tgz#9f1762efe6f3365f0bf3b019cc9bd1629d19bc50"
+  integrity sha512-k/1pb70eD638anoi0e8wUGAlbMJXyvdV4p62Ko+EZ7eBe1xMx8Uhak1R5DgfoofsK5IBBnRwsYGTaLZl+6/+RQ==
+  dependencies:
+    content-type "^1.0.5"
+    cors "^2.8.5"
+    cross-spawn "^7.0.3"
+    eventsource "^3.0.2"
+    express "^5.0.1"
+    express-rate-limit "^7.5.0"
+    pkce-challenge "^5.0.0"
+    raw-body "^3.0.0"
+    zod "^3.23.8"
+    zod-to-json-schema "^3.24.1"
+
 "@mrmlnc/readdir-enhanced@^2.2.1":
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@@ -330,7 +391,7 @@
   resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
   integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
 
-"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
+"@nodelib/fs.walk@^1.2.3":
   version "1.2.8"
   resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
   integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
@@ -338,6 +399,16 @@
     "@nodelib/fs.scandir" "2.1.5"
     fastq "^1.6.0"
 
+"@pkgr/core@^0.1.0":
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.2.tgz#1cf95080bb7072fafaa3cb13b442fab4695c3893"
+  integrity sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==
+
+"@pkgr/core@^0.2.4":
+  version "0.2.4"
+  resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c"
+  integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==
+
 "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
@@ -391,126 +462,125 @@
   resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
   integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
 
-"@rollup/plugin-node-resolve@^13.0.4":
-  version "13.3.0"
-  resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz#da1c5c5ce8316cef96a2f823d111c1e4e498801c"
-  integrity sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==
+"@rollup/plugin-node-resolve@^15.0.1":
+  version "15.3.1"
+  resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz#66008953c2524be786aa319d49e32f2128296a78"
+  integrity sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==
   dependencies:
-    "@rollup/pluginutils" "^3.1.0"
-    "@types/resolve" "1.17.1"
+    "@rollup/pluginutils" "^5.0.1"
+    "@types/resolve" "1.20.2"
     deepmerge "^4.2.2"
-    is-builtin-module "^3.1.0"
     is-module "^1.0.0"
-    resolve "^1.19.0"
+    resolve "^1.22.1"
 
-"@rollup/pluginutils@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
-  integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
+"@rollup/pluginutils@^5.0.1":
+  version "5.1.4"
+  resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz#bb94f1f9eaaac944da237767cdfee6c5b2262d4a"
+  integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==
   dependencies:
-    "@types/estree" "0.0.39"
-    estree-walker "^1.0.1"
-    picomatch "^2.2.2"
+    "@types/estree" "^1.0.0"
+    estree-walker "^2.0.2"
+    picomatch "^4.0.2"
 
-"@rollup/rollup-android-arm-eabi@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz#d964ee8ce4d18acf9358f96adc408689b6e27fe3"
-  integrity sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==
+"@rollup/rollup-android-arm-eabi@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz#9145b38faf3fbfe3ec557130110e772f797335aa"
+  integrity sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==
 
-"@rollup/rollup-android-arm64@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz#9b5e130ecc32a5fc1e96c09ff371743ee71a62d3"
-  integrity sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==
+"@rollup/rollup-android-arm64@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz#d73d641c59e9d7827e5ce0af9dfbc168b95cce0f"
+  integrity sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==
 
-"@rollup/rollup-darwin-arm64@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz#ef439182c739b20b3c4398cfc03e3c1249ac8903"
-  integrity sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==
+"@rollup/rollup-darwin-arm64@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz#45d9d71d941117c98e7a5e77f60f0bc682d27e82"
+  integrity sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==
 
-"@rollup/rollup-darwin-x64@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz#d7380c1531ab0420ca3be16f17018ef72dd3d504"
-  integrity sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==
+"@rollup/rollup-darwin-x64@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz#8d72fb5f81714cb43e90f263fb1674520cce3f2a"
+  integrity sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==
 
-"@rollup/rollup-freebsd-arm64@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz#cbcbd7248823c6b430ce543c59906dd3c6df0936"
-  integrity sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==
+"@rollup/rollup-freebsd-arm64@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz#a52b58852c9cec9255e382a2f335b08bc8c6111d"
+  integrity sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==
 
-"@rollup/rollup-freebsd-x64@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz#96bf6ff875bab5219c3472c95fa6eb992586a93b"
-  integrity sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==
+"@rollup/rollup-freebsd-x64@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz#104511dc64612789ddda41d164ab07cdac84a6c1"
+  integrity sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==
 
-"@rollup/rollup-linux-arm-gnueabihf@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz#d80cd62ce6d40f8e611008d8dbf03b5e6bbf009c"
-  integrity sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==
+"@rollup/rollup-linux-arm-gnueabihf@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz#643e3ad19c93903201fde89abd76baaee725e6c2"
+  integrity sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==
 
-"@rollup/rollup-linux-arm-musleabihf@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz#75440cfc1e8d0f87a239b4c31dfeaf4719b656b7"
-  integrity sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==
+"@rollup/rollup-linux-arm-musleabihf@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz#fdc6a595aec7b20c5bfdac81412028c56d734e63"
+  integrity sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==
 
-"@rollup/rollup-linux-arm64-gnu@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz#ac527485ecbb619247fb08253ec8c551a0712e7c"
-  integrity sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==
+"@rollup/rollup-linux-arm64-gnu@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz#c28620bcd385496bdbbc24920b21f9fcca9ecbfa"
+  integrity sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==
 
-"@rollup/rollup-linux-arm64-musl@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz#74d2b5cb11cf714cd7d1682e7c8b39140e908552"
-  integrity sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==
+"@rollup/rollup-linux-arm64-musl@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz#a6b71b1e8fa33bac9f65b6f879e8ed878035d120"
+  integrity sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==
 
-"@rollup/rollup-linux-loongarch64-gnu@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz#a0a310e51da0b5fea0e944b0abd4be899819aef6"
-  integrity sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==
+"@rollup/rollup-linux-loongarch64-gnu@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz#b06374601ce865a1110324b2f06db574d3a1b0e1"
+  integrity sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==
 
-"@rollup/rollup-linux-powerpc64le-gnu@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz#4077e2862b0ac9f61916d6b474d988171bd43b83"
-  integrity sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==
+"@rollup/rollup-linux-powerpc64le-gnu@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz#8a2a1f6058c920889c2aff3753a20fead7a8cc26"
+  integrity sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==
 
-"@rollup/rollup-linux-riscv64-gnu@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz#5812a1a7a2f9581cbe12597307cc7ba3321cf2f3"
-  integrity sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==
+"@rollup/rollup-linux-riscv64-gnu@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz#8ef6f680d011b95a2f6546c6c31a37a33138035f"
+  integrity sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==
 
-"@rollup/rollup-linux-riscv64-musl@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz#973aaaf4adef4531375c36616de4e01647f90039"
-  integrity sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==
+"@rollup/rollup-linux-riscv64-musl@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz#9f4884c5955a7cd39b396f6e27aa59b3269988eb"
+  integrity sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==
 
-"@rollup/rollup-linux-s390x-gnu@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz#9bad59e907ba5bfcf3e9dbd0247dfe583112f70b"
-  integrity sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==
+"@rollup/rollup-linux-s390x-gnu@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz#5619303cc51994e3df404a497f42c79dc5efd6eb"
+  integrity sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==
 
-"@rollup/rollup-linux-x64-gnu@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz#68b045a720bd9b4d905f462b997590c2190a6de0"
-  integrity sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==
+"@rollup/rollup-linux-x64-gnu@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz#c3e42b66c04e25ad0f2a00beec42ede96ccc8983"
+  integrity sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==
 
-"@rollup/rollup-linux-x64-musl@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz#8e703e2c2ad19ba7b2cb3d8c3a4ad11d4ee3a282"
-  integrity sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==
+"@rollup/rollup-linux-x64-musl@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.0.tgz#8d3452de42aa72fc5fc3e5ad1eb0b68030742a25"
+  integrity sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==
 
-"@rollup/rollup-win32-arm64-msvc@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz#c5bee19fa670ff5da5f066be6a58b4568e9c650b"
-  integrity sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==
+"@rollup/rollup-win32-arm64-msvc@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz#3b7bbd9f43f1c380061f306abce6f3f64de20306"
+  integrity sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==
 
-"@rollup/rollup-win32-ia32-msvc@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz#846e02c17044bd922f6f483a3b4d36aac6e2b921"
-  integrity sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==
+"@rollup/rollup-win32-ia32-msvc@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz#e27ef5c40bbec49fac3d4e4b1618fbe4597b40e5"
+  integrity sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==
 
-"@rollup/rollup-win32-x64-msvc@4.40.0":
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz#fd92d31a2931483c25677b9c6698106490cbbc76"
-  integrity sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==
+"@rollup/rollup-win32-x64-msvc@4.41.0":
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz#b0b595ad4720259bbb81600750d26a655cac06be"
+  integrity sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==
 
 "@rtsao/scc@^1.1.0":
   version "1.1.0"
@@ -550,29 +620,32 @@
   integrity sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==
 
 "@types/cookies@*":
-  version "0.7.10"
-  resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.10.tgz#c4881dca4dd913420c488508d192496c46eb4fd0"
-  integrity sha512-hmUCjAk2fwZVPPkkPBcI7jGLIR5mg4OVoNMBwU6aVsMm/iNPY7z9/R+x2fSwLt/ZXoGua6C5Zy2k5xOo9jUyhQ==
+  version "0.9.0"
+  resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.9.0.tgz#a2290cfb325f75f0f28720939bee854d4142aee2"
+  integrity sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q==
   dependencies:
     "@types/connect" "*"
     "@types/express" "*"
     "@types/keygrip" "*"
     "@types/node" "*"
 
-"@types/estree@0.0.39":
-  version "0.0.39"
-  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
-  integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
+"@types/eslint@^9.6.1":
+  version "9.6.1"
+  resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.1.tgz#d5795ad732ce81715f27f75da913004a56751584"
+  integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==
+  dependencies:
+    "@types/estree" "*"
+    "@types/json-schema" "*"
 
-"@types/estree@1.0.7":
+"@types/estree@*", "@types/estree@1.0.7", "@types/estree@^1.0.0", "@types/estree@^1.0.6":
   version "1.0.7"
   resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8"
   integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==
 
-"@types/express-serve-static-core@^4.17.33":
-  version "4.17.41"
-  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz#5077defa630c2e8d28aa9ffc2c01c157c305bef6"
-  integrity sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==
+"@types/express-serve-static-core@^5.0.0":
+  version "5.0.6"
+  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz#41fec4ea20e9c7b22f024ab88a95c6bb288f51b8"
+  integrity sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==
   dependencies:
     "@types/node" "*"
     "@types/qs" "*"
@@ -580,26 +653,25 @@
     "@types/send" "*"
 
 "@types/express@*":
-  version "4.17.21"
-  resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d"
-  integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.2.tgz#7be9e337a5745d6b43ef5b0c352dad94a7f0c256"
+  integrity sha512-BtjL3ZwbCQriyb0DGw+Rt12qAXPiBTPs815lsUvtt1Grk0vLRMZNMUZ741d5rjk+UQOxfDiBZ3dxpX00vSkK3g==
   dependencies:
     "@types/body-parser" "*"
-    "@types/express-serve-static-core" "^4.17.33"
-    "@types/qs" "*"
+    "@types/express-serve-static-core" "^5.0.0"
     "@types/serve-static" "*"
 
 "@types/http-assert@*":
-  version "1.5.5"
-  resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.5.tgz#dfb1063eb7c240ee3d3fe213dac5671cfb6a8dbf"
-  integrity sha512-4+tE/lwdAahgZT1g30Jkdm9PzFRde0xwxBNUyRsCitRvCQB90iuA2uJYdUnhnANRcqGXaWOGY4FEoxeElNAK2g==
+  version "1.5.6"
+  resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.6.tgz#b6b657c38a2350d21ce213139f33b03b2b5fa431"
+  integrity sha512-TTEwmtjgVbYAzZYWyeHPrrtWnfVkm8tQkP8P21uQifPgMRgjrow3XDEYqucuC8SKZJT7pUnhU/JymvjggxO9vw==
 
 "@types/http-errors@*":
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
   integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==
 
-"@types/json-schema@^7.0.9":
+"@types/json-schema@*", "@types/json-schema@^7.0.15":
   version "7.0.15"
   resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
   integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
@@ -622,9 +694,9 @@
     "@types/koa" "*"
 
 "@types/koa@*", "@types/koa@^2.11.6":
-  version "2.13.12"
-  resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.12.tgz#70d87a9061a81909e0ee11ca50168416e8d3e795"
-  integrity sha512-vAo1KuDSYWFDB4Cs80CHvfmzSQWeUb909aQib0C0aFx4sw0K9UZFz2m5jaEP+b3X1+yr904iQiruS0hXi31jbw==
+  version "2.15.0"
+  resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.15.0.tgz#eca43d76f527c803b491731f95df575636e7b6f2"
+  integrity sha512-7QFsywoE5URbuVnG3loe03QXuGajrnotr3gQkXcEBShORai23MePfFYdhz90FEtBBpkyIYQbVD+evKtloCgX3g==
   dependencies:
     "@types/accepts" "*"
     "@types/content-disposition" "*"
@@ -640,11 +712,6 @@
   resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
   integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
 
-"@types/mime@*":
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45"
-  integrity sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==
-
 "@types/mime@^1":
   version "1.3.5"
   resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
@@ -656,11 +723,11 @@
   integrity sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==
 
 "@types/node@*":
-  version "20.10.6"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.6.tgz#a3ec84c22965802bf763da55b2394424f22bfbb5"
-  integrity sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==
+  version "22.15.18"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.18.tgz#2f8240f7e932f571c2d45f555ba0b6c3f7a75963"
+  integrity sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg==
   dependencies:
-    undici-types "~5.26.4"
+    undici-types "~6.21.0"
 
 "@types/node@^10.1.0":
   version "10.17.60"
@@ -683,26 +750,19 @@
   integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==
 
 "@types/qs@*":
-  version "6.9.11"
-  resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.11.tgz#208d8a30bc507bd82e03ada29e4732ea46a6bbda"
-  integrity sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==
+  version "6.14.0"
+  resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.14.0.tgz#d8b60cecf62f2db0fb68e5e006077b9178b85de5"
+  integrity sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==
 
 "@types/range-parser@*":
   version "1.2.7"
   resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb"
   integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
 
-"@types/resolve@1.17.1":
-  version "1.17.1"
-  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
-  integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
-  dependencies:
-    "@types/node" "*"
-
-"@types/semver@^7.3.12":
-  version "7.5.6"
-  resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339"
-  integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==
+"@types/resolve@1.20.2":
+  version "1.20.2"
+  resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975"
+  integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==
 
 "@types/send@*":
   version "0.17.4"
@@ -713,13 +773,13 @@
     "@types/node" "*"
 
 "@types/serve-static@*":
-  version "1.15.5"
-  resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.5.tgz#15e67500ec40789a1e8c9defc2d32a896f05b033"
-  integrity sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==
+  version "1.15.7"
+  resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714"
+  integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==
   dependencies:
     "@types/http-errors" "*"
-    "@types/mime" "*"
     "@types/node" "*"
+    "@types/send" "*"
 
 "@types/ws@^7.4.0":
   version "7.4.7"
@@ -728,111 +788,106 @@
   dependencies:
     "@types/node" "*"
 
-"@typescript-eslint/eslint-plugin@^4.2.0", "@typescript-eslint/eslint-plugin@^5.62.0":
-  version "5.62.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db"
-  integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==
+"@typescript-eslint/eslint-plugin@5.62.0", "@typescript-eslint/eslint-plugin@^8.32.0":
+  version "8.32.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz#86630dd3084f9d6c4239bbcd6a7ee1a7ee844f7f"
+  integrity sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==
   dependencies:
-    "@eslint-community/regexpp" "^4.4.0"
-    "@typescript-eslint/scope-manager" "5.62.0"
-    "@typescript-eslint/type-utils" "5.62.0"
-    "@typescript-eslint/utils" "5.62.0"
-    debug "^4.3.4"
+    "@eslint-community/regexpp" "^4.10.0"
+    "@typescript-eslint/scope-manager" "8.32.0"
+    "@typescript-eslint/type-utils" "8.32.0"
+    "@typescript-eslint/utils" "8.32.0"
+    "@typescript-eslint/visitor-keys" "8.32.0"
     graphemer "^1.4.0"
-    ignore "^5.2.0"
-    natural-compare-lite "^1.4.0"
-    semver "^7.3.7"
-    tsutils "^3.21.0"
+    ignore "^5.3.1"
+    natural-compare "^1.4.0"
+    ts-api-utils "^2.1.0"
 
-"@typescript-eslint/parser@^4.2.0", "@typescript-eslint/parser@^5.62.0":
-  version "5.62.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7"
-  integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==
+"@typescript-eslint/parser@5.62.0", "@typescript-eslint/parser@^8.32.0":
+  version "8.32.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.32.0.tgz#fe840ecb2726a82fa9f5562837ec40503ae71caf"
+  integrity sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==
   dependencies:
-    "@typescript-eslint/scope-manager" "5.62.0"
-    "@typescript-eslint/types" "5.62.0"
-    "@typescript-eslint/typescript-estree" "5.62.0"
+    "@typescript-eslint/scope-manager" "8.32.0"
+    "@typescript-eslint/types" "8.32.0"
+    "@typescript-eslint/typescript-estree" "8.32.0"
+    "@typescript-eslint/visitor-keys" "8.32.0"
     debug "^4.3.4"
 
-"@typescript-eslint/scope-manager@5.62.0":
-  version "5.62.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c"
-  integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==
+"@typescript-eslint/scope-manager@8.32.0":
+  version "8.32.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.32.0.tgz#6be89f652780f0d3d19d58dc0ee107b1a9e3282c"
+  integrity sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==
   dependencies:
-    "@typescript-eslint/types" "5.62.0"
-    "@typescript-eslint/visitor-keys" "5.62.0"
+    "@typescript-eslint/types" "8.32.0"
+    "@typescript-eslint/visitor-keys" "8.32.0"
 
-"@typescript-eslint/type-utils@5.62.0":
-  version "5.62.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a"
-  integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==
+"@typescript-eslint/type-utils@8.32.0":
+  version "8.32.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.32.0.tgz#5e0882393e801963f749bea38888e716045fe895"
+  integrity sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==
   dependencies:
-    "@typescript-eslint/typescript-estree" "5.62.0"
-    "@typescript-eslint/utils" "5.62.0"
+    "@typescript-eslint/typescript-estree" "8.32.0"
+    "@typescript-eslint/utils" "8.32.0"
     debug "^4.3.4"
-    tsutils "^3.21.0"
+    ts-api-utils "^2.1.0"
 
-"@typescript-eslint/types@5.62.0":
-  version "5.62.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
-  integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
+"@typescript-eslint/types@8.32.0":
+  version "8.32.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.32.0.tgz#a4a66b8876b8391970cf069b49572e43f1fc957a"
+  integrity sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==
 
-"@typescript-eslint/typescript-estree@5.62.0":
-  version "5.62.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b"
-  integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==
+"@typescript-eslint/types@^8.11.0":
+  version "8.32.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.32.1.tgz#b19fe4ac0dc08317bae0ce9ec1168123576c1d4b"
+  integrity sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==
+
+"@typescript-eslint/typescript-estree@8.32.0":
+  version "8.32.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.0.tgz#11d45f47bfabb141206a3da6c7b91a9d869ff32d"
+  integrity sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==
   dependencies:
-    "@typescript-eslint/types" "5.62.0"
-    "@typescript-eslint/visitor-keys" "5.62.0"
+    "@typescript-eslint/types" "8.32.0"
+    "@typescript-eslint/visitor-keys" "8.32.0"
     debug "^4.3.4"
-    globby "^11.1.0"
+    fast-glob "^3.3.2"
     is-glob "^4.0.3"
-    semver "^7.3.7"
-    tsutils "^3.21.0"
+    minimatch "^9.0.4"
+    semver "^7.6.0"
+    ts-api-utils "^2.1.0"
 
-"@typescript-eslint/utils@5.62.0":
-  version "5.62.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86"
-  integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==
+"@typescript-eslint/utils@8.32.0":
+  version "8.32.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.32.0.tgz#24570f68cf845d198b73a7f94ca88d8c2505ba47"
+  integrity sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==
   dependencies:
-    "@eslint-community/eslint-utils" "^4.2.0"
-    "@types/json-schema" "^7.0.9"
-    "@types/semver" "^7.3.12"
-    "@typescript-eslint/scope-manager" "5.62.0"
-    "@typescript-eslint/types" "5.62.0"
-    "@typescript-eslint/typescript-estree" "5.62.0"
-    eslint-scope "^5.1.1"
-    semver "^7.3.7"
+    "@eslint-community/eslint-utils" "^4.7.0"
+    "@typescript-eslint/scope-manager" "8.32.0"
+    "@typescript-eslint/types" "8.32.0"
+    "@typescript-eslint/typescript-estree" "8.32.0"
 
-"@typescript-eslint/visitor-keys@5.62.0":
-  version "5.62.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e"
-  integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==
+"@typescript-eslint/visitor-keys@8.32.0":
+  version "8.32.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.0.tgz#0cca2cac046bc71cc40ce8214bac2850d6ecf4a6"
+  integrity sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==
   dependencies:
-    "@typescript-eslint/types" "5.62.0"
-    eslint-visitor-keys "^3.3.0"
+    "@typescript-eslint/types" "8.32.0"
+    eslint-visitor-keys "^4.2.0"
 
-"@ungap/structured-clone@^1.2.0":
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
-  integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
+"@web/config-loader@^0.3.0":
+  version "0.3.3"
+  resolved "https://registry.yarnpkg.com/@web/config-loader/-/config-loader-0.3.3.tgz#13d4852c479d1f3adbc1f24d79c7e6eeedeb6e5d"
+  integrity sha512-ilzeQzrPpPLWZhzFCV+4doxKDGm7oKVfdKpW9wiUNVgive34NSzCw+WzXTvjE4Jgr5CkyTDIObEmMrqQEjhT0g==
 
-"@web/config-loader@^0.1.3":
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/@web/config-loader/-/config-loader-0.1.3.tgz#8325ea54f75ef2ee7166783e64e66936db25bff7"
-  integrity sha512-XVKH79pk4d3EHRhofete8eAnqto1e8mCRAqPV00KLNFzCWSe8sWmLnqKCqkPNARC6nksMaGrATnA5sPDRllMpQ==
-  dependencies:
-    semver "^7.3.4"
-
-"@web/dev-server-core@^0.4.1":
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/@web/dev-server-core/-/dev-server-core-0.4.1.tgz#803faff45281ee296d0dda02dfdd905c330db4d8"
-  integrity sha512-KdYwejXZwIZvb6tYMCqU7yBiEOPfKLQ3V9ezqqEz8DA9V9R3oQWaowckvCpFB9IxxPfS/P8/59OkdzGKQjcIUw==
+"@web/dev-server-core@^0.7.2", "@web/dev-server-core@^0.7.4":
+  version "0.7.5"
+  resolved "https://registry.yarnpkg.com/@web/dev-server-core/-/dev-server-core-0.7.5.tgz#b283d46eb2c0384e848311ec9da25d06bbbc47df"
+  integrity sha512-Da65zsiN6iZPMRuj4Oa6YPwvsmZmo5gtPWhW2lx3GTUf5CAEapjVpZVlUXnKPL7M7zRuk72jSsIl8lo+XpTCtw==
   dependencies:
     "@types/koa" "^2.11.6"
     "@types/ws" "^7.4.0"
-    "@web/parse5-utils" "^1.3.1"
-    chokidar "^3.4.3"
+    "@web/parse5-utils" "^2.1.0"
+    chokidar "^4.0.1"
     clone "^2.1.2"
     es-module-lexer "^1.0.0"
     get-stream "^6.0.0"
@@ -842,59 +897,59 @@
     koa-etag "^4.0.0"
     koa-send "^5.0.1"
     koa-static "^5.0.0"
-    lru-cache "^6.0.0"
+    lru-cache "^8.0.4"
     mime-types "^2.1.27"
     parse5 "^6.0.1"
     picomatch "^2.2.2"
-    ws "^7.4.2"
+    ws "^7.5.10"
 
-"@web/dev-server-esbuild@^0.3.6":
-  version "0.3.6"
-  resolved "https://registry.yarnpkg.com/@web/dev-server-esbuild/-/dev-server-esbuild-0.3.6.tgz#838100894937443b96bfc4266c7795d27ed4afac"
-  integrity sha512-VDcZOzvmbg/z/8Q54hHqFwt9U4cacQJZxgS8YXAvyFuG85HAJ/Q55P7Tr++1NlRS8wQEos6QK2ERUWNjEVOhqQ==
+"@web/dev-server-esbuild@^1.0.4":
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/@web/dev-server-esbuild/-/dev-server-esbuild-1.0.4.tgz#7ac39eb4350da39fb3f7c5ce5c0fd423a8511346"
+  integrity sha512-ia1LxBwwRiQBYhJ7/RtLenHyPjzle3SvTw3jOZaeGv8UGXVPOkQV8fR05caOtW/DPPZaZovNAybzRKVnNiYIZg==
   dependencies:
     "@mdn/browser-compat-data" "^4.0.0"
-    "@web/dev-server-core" "^0.4.1"
-    esbuild "^0.16 || ^0.17"
+    "@web/dev-server-core" "^0.7.4"
+    esbuild "^0.25.0"
     parse5 "^6.0.1"
     ua-parser-js "^1.0.33"
 
-"@web/dev-server-rollup@^0.4.1":
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/@web/dev-server-rollup/-/dev-server-rollup-0.4.1.tgz#3c6606bac8e497498b5b47bf9e0c544c321b38ef"
-  integrity sha512-Ebsv7Ovd9MufeH3exvikBJ7GmrZA5OmHnOgaiHcwMJ2eQBJA5/I+/CbRjsLX97ICj/ZwZG//p2ITRz8W3UfSqg==
+"@web/dev-server-rollup@^0.6.1":
+  version "0.6.4"
+  resolved "https://registry.yarnpkg.com/@web/dev-server-rollup/-/dev-server-rollup-0.6.4.tgz#d0a4f69e4a659d2b79f172e86236cea6c872e81c"
+  integrity sha512-sJZfTGCCrdku5xYnQQG51odGI092hKY9YFM0X3Z0tRY3iXKXcYRaLZrErw5KfCxr6g0JRuhe4BBhqXTA5Q2I3Q==
   dependencies:
-    "@rollup/plugin-node-resolve" "^13.0.4"
-    "@web/dev-server-core" "^0.4.1"
+    "@rollup/plugin-node-resolve" "^15.0.1"
+    "@web/dev-server-core" "^0.7.2"
     nanocolors "^0.2.1"
     parse5 "^6.0.1"
-    rollup "^2.67.0"
-    whatwg-url "^11.0.0"
+    rollup "^4.4.0"
+    whatwg-url "^14.0.0"
 
-"@web/dev-server@^0.1.38":
-  version "0.1.38"
-  resolved "https://registry.yarnpkg.com/@web/dev-server/-/dev-server-0.1.38.tgz#d755092d66aeb923c546237a6c460439ea3ddd29"
-  integrity sha512-WUq7Zi8KeJ5/UZmmpZ+kzUpUlFlMP/rcreJKYg9Lxiz998KYl4G5Rv24akX0piTuqXG7r6h+zszg8V/hdzjCoA==
+"@web/dev-server@^0.4.6":
+  version "0.4.6"
+  resolved "https://registry.yarnpkg.com/@web/dev-server/-/dev-server-0.4.6.tgz#18a4421d474a9bd1bfc90419a7a798ed0b5538c5"
+  integrity sha512-jj/1bcElAy5EZet8m2CcUdzxT+CRvUjIXGh8Lt7vxtthkN9PzY9wlhWx/9WOs5iwlnG1oj0VGo6f/zvbPO0s9w==
   dependencies:
     "@babel/code-frame" "^7.12.11"
     "@types/command-line-args" "^5.0.0"
-    "@web/config-loader" "^0.1.3"
-    "@web/dev-server-core" "^0.4.1"
-    "@web/dev-server-rollup" "^0.4.1"
+    "@web/config-loader" "^0.3.0"
+    "@web/dev-server-core" "^0.7.2"
+    "@web/dev-server-rollup" "^0.6.1"
     camelcase "^6.2.0"
     command-line-args "^5.1.1"
     command-line-usage "^7.0.1"
     debounce "^1.2.0"
     deepmerge "^4.2.2"
-    ip "^1.1.5"
+    internal-ip "^6.2.0"
     nanocolors "^0.2.1"
     open "^8.0.2"
     portfinder "^1.0.32"
 
-"@web/parse5-utils@^1.3.1":
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/@web/parse5-utils/-/parse5-utils-1.3.1.tgz#6727be4d7875a9ecb96a5b3003bd271da763f8b4"
-  integrity sha512-haCgDchZrAOB9EhBJ5XqiIjBMsS/exsM5Ru7sCSyNkXVEJWskyyKuKMFk66BonnIGMPpDtqDrTUfYEis5Zi3XA==
+"@web/parse5-utils@^2.1.0":
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/@web/parse5-utils/-/parse5-utils-2.1.0.tgz#3d33aca62c66773492f2fba89d23a45f8b57ba4a"
+  integrity sha512-GzfK5disEJ6wEjoPwx8AVNwUe9gYIiwc+x//QYxYDAFKUp4Xb1OJAGLc2l2gVrSQmtPGLKrTRcW90Hv4pEq1qA==
   dependencies:
     "@types/parse5" "^6.0.1"
     parse5 "^6.0.1"
@@ -907,21 +962,24 @@
     mime-types "~2.1.34"
     negotiator "0.6.3"
 
+accepts@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895"
+  integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==
+  dependencies:
+    mime-types "^3.0.0"
+    negotiator "^1.0.0"
+
 acorn-jsx@^5.3.2:
   version "5.3.2"
   resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
   integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
 
-acorn@^8.8.2:
+acorn@^8.14.0:
   version "8.14.1"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb"
   integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==
 
-acorn@^8.9.0:
-  version "8.14.0"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0"
-  integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
-
 ajv@^6.12.4:
   version "6.12.6"
   resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
@@ -958,14 +1016,6 @@
   dependencies:
     color-convert "^2.0.1"
 
-anymatch@~3.1.2:
-  version "3.1.3"
-  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
-  integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
-  dependencies:
-    normalize-path "^3.0.0"
-    picomatch "^2.0.4"
-
 are-docs-informative@^0.0.2:
   version "0.0.2"
   resolved "https://registry.yarnpkg.com/are-docs-informative/-/are-docs-informative-0.0.2.tgz#387f0e93f5d45280373d387a59d34c96db321963"
@@ -1001,13 +1051,13 @@
   resolved "https://registry.yarnpkg.com/array-back/-/array-back-6.2.2.tgz#f567d99e9af88a6d3d2f9dfcc21db6f9ba9fd157"
   integrity sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==
 
-array-buffer-byte-length@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f"
-  integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==
+array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b"
+  integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==
   dependencies:
-    call-bind "^1.0.5"
-    is-array-buffer "^3.0.4"
+    call-bound "^1.0.3"
+    is-array-buffer "^3.0.5"
 
 array-includes@^3.1.8:
   version "3.1.8"
@@ -1021,61 +1071,56 @@
     get-intrinsic "^1.2.4"
     is-string "^1.0.7"
 
-array-union@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
-  integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-
 array-unique@^0.3.2:
   version "0.3.2"
   resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
   integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==
 
 array.prototype.findlastindex@^1.2.5:
-  version "1.2.5"
-  resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d"
-  integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==
+  version "1.2.6"
+  resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz#cfa1065c81dcb64e34557c9b81d012f6a421c564"
+  integrity sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==
   dependencies:
-    call-bind "^1.0.7"
+    call-bind "^1.0.8"
+    call-bound "^1.0.4"
     define-properties "^1.2.1"
-    es-abstract "^1.23.2"
+    es-abstract "^1.23.9"
     es-errors "^1.3.0"
-    es-object-atoms "^1.0.0"
-    es-shim-unscopables "^1.0.2"
+    es-object-atoms "^1.1.1"
+    es-shim-unscopables "^1.1.0"
 
 array.prototype.flat@^1.3.2:
-  version "1.3.2"
-  resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18"
-  integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5"
+  integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==
   dependencies:
-    call-bind "^1.0.2"
-    define-properties "^1.2.0"
-    es-abstract "^1.22.1"
-    es-shim-unscopables "^1.0.0"
+    call-bind "^1.0.8"
+    define-properties "^1.2.1"
+    es-abstract "^1.23.5"
+    es-shim-unscopables "^1.0.2"
 
 array.prototype.flatmap@^1.3.2:
-  version "1.3.2"
-  resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527"
-  integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b"
+  integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==
   dependencies:
-    call-bind "^1.0.2"
-    define-properties "^1.2.0"
-    es-abstract "^1.22.1"
-    es-shim-unscopables "^1.0.0"
+    call-bind "^1.0.8"
+    define-properties "^1.2.1"
+    es-abstract "^1.23.5"
+    es-shim-unscopables "^1.0.2"
 
-arraybuffer.prototype.slice@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6"
-  integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==
+arraybuffer.prototype.slice@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c"
+  integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==
   dependencies:
     array-buffer-byte-length "^1.0.1"
-    call-bind "^1.0.5"
+    call-bind "^1.0.8"
     define-properties "^1.2.1"
-    es-abstract "^1.22.3"
-    es-errors "^1.2.1"
-    get-intrinsic "^1.2.3"
+    es-abstract "^1.23.5"
+    es-errors "^1.3.0"
+    get-intrinsic "^1.2.6"
     is-array-buffer "^3.0.4"
-    is-shared-array-buffer "^1.0.2"
 
 arrify@^1.0.1:
   version "1.0.1"
@@ -1087,12 +1132,15 @@
   resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
   integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==
 
-async@^2.6.4:
-  version "2.6.4"
-  resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
-  integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==
-  dependencies:
-    lodash "^4.17.14"
+async-function@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b"
+  integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==
+
+async@^3.2.6:
+  version "3.2.6"
+  resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce"
+  integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==
 
 atob@^2.1.2:
   version "2.1.2"
@@ -1124,10 +1172,20 @@
     mixin-deep "^1.2.0"
     pascalcase "^0.1.1"
 
-binary-extensions@^2.0.0:
+body-parser@^2.2.0:
   version "2.2.0"
-  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
-  integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.0.tgz#f7a9656de305249a715b549b7b8fd1ab9dfddcfa"
+  integrity sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==
+  dependencies:
+    bytes "^3.1.2"
+    content-type "^1.0.5"
+    debug "^4.4.0"
+    http-errors "^2.0.0"
+    iconv-lite "^0.6.3"
+    on-finished "^2.4.1"
+    qs "^6.14.0"
+    raw-body "^3.0.0"
+    type-is "^2.0.0"
 
 brace-expansion@^1.1.7:
   version "1.1.11"
@@ -1137,6 +1195,13 @@
     balanced-match "^1.0.0"
     concat-map "0.0.1"
 
+brace-expansion@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+  integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+  dependencies:
+    balanced-match "^1.0.0"
+
 braces@^2.3.1:
   version "2.3.2"
   resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
@@ -1153,22 +1218,29 @@
     split-string "^3.0.2"
     to-regex "^3.0.1"
 
-braces@^3.0.2, braces@~3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
-  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+braces@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+  integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
   dependencies:
-    fill-range "^7.0.1"
+    fill-range "^7.1.1"
 
 buffer-from@^1.0.0:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
   integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
 
-builtin-modules@^3.3.0:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
-  integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
+builtins@^5.0.1:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.1.0.tgz#6d85eeb360c4ebc166c3fdef922a15aa7316a5e8"
+  integrity sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==
+  dependencies:
+    semver "^7.0.0"
+
+bytes@3.1.2, bytes@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+  integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
 
 cache-base@^1.0.1:
   version "1.0.1"
@@ -1193,16 +1265,31 @@
     mime-types "^2.1.18"
     ylru "^1.2.0"
 
-call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
-  version "1.0.7"
-  resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
-  integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
+call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
+  integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
   dependencies:
-    es-define-property "^1.0.0"
     es-errors "^1.3.0"
     function-bind "^1.1.2"
+
+call-bind@^1.0.7, call-bind@^1.0.8:
+  version "1.0.8"
+  resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c"
+  integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==
+  dependencies:
+    call-bind-apply-helpers "^1.0.0"
+    es-define-property "^1.0.0"
     get-intrinsic "^1.2.4"
-    set-function-length "^1.2.1"
+    set-function-length "^1.2.2"
+
+call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a"
+  integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==
+  dependencies:
+    call-bind-apply-helpers "^1.0.2"
+    get-intrinsic "^1.3.0"
 
 call-me-maybe@^1.0.1:
   version "1.0.2"
@@ -1262,20 +1349,12 @@
   resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
   integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
 
-chokidar@^3.4.3:
-  version "3.5.3"
-  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
-  integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+chokidar@^4.0.1:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30"
+  integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==
   dependencies:
-    anymatch "~3.1.2"
-    braces "~3.0.2"
-    glob-parent "~5.1.2"
-    is-binary-path "~2.1.0"
-    is-glob "~4.0.1"
-    normalize-path "~3.0.0"
-    readdirp "~3.6.0"
-  optionalDependencies:
-    fsevents "~2.3.2"
+    readdirp "^4.0.1"
 
 class-utils@^0.3.5:
   version "0.3.6"
@@ -1350,7 +1429,7 @@
   resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
   integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
 
-command-line-args@^5.1.1, command-line-args@^5.2.1:
+command-line-args@^5.1.1:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e"
   integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==
@@ -1360,14 +1439,14 @@
     lodash.camelcase "^4.3.0"
     typical "^4.0.0"
 
-command-line-usage@^7.0.0, command-line-usage@^7.0.1:
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-7.0.1.tgz#e540afef4a4f3bc501b124ffde33956309100655"
-  integrity sha512-NCyznE//MuTjwi3y84QVUGEOT+P5oto1e1Pk/jFPVdPPfsG03qpTIl3yw6etR+v73d0lXsoojRpvbru2sqePxQ==
+command-line-usage@^7.0.1:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-7.0.3.tgz#6bce992354f6af10ecea2b631bfdf0c8b3bfaea3"
+  integrity sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==
   dependencies:
     array-back "^6.2.2"
     chalk-template "^0.4.0"
-    table-layout "^3.0.0"
+    table-layout "^4.1.0"
     typical "^7.1.1"
 
 commander@^2.20.0:
@@ -1375,10 +1454,10 @@
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
   integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
 
-comment-parser@1.3.1:
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.1.tgz#3d7ea3adaf9345594aedee6563f422348f165c1b"
-  integrity sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==
+comment-parser@1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc"
+  integrity sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==
 
 component-emitter@^1.2.1:
   version "1.3.1"
@@ -1390,6 +1469,13 @@
   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
   integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
 
+content-disposition@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.0.tgz#844426cb398f934caefcbb172200126bc7ceace2"
+  integrity sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==
+  dependencies:
+    safe-buffer "5.2.1"
+
 content-disposition@~0.5.2:
   version "0.5.4"
   resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
@@ -1397,11 +1483,21 @@
   dependencies:
     safe-buffer "5.2.1"
 
-content-type@^1.0.4:
+content-type@^1.0.4, content-type@^1.0.5:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
   integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
 
+cookie-signature@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793"
+  integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==
+
+cookie@^0.7.1:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7"
+  integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
+
 cookies@~0.9.0:
   version "0.9.1"
   resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.9.1.tgz#3ffed6f60bb4fb5f146feeedba50acc418af67e3"
@@ -1415,10 +1511,18 @@
   resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
   integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==
 
+cors@^2.8.5:
+  version "2.8.5"
+  resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
+  integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
+  dependencies:
+    object-assign "^4"
+    vary "^1"
+
 cross-spawn@^6.0.5:
-  version "6.0.5"
-  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
-  integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
+  version "6.0.6"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57"
+  integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==
   dependencies:
     nice-try "^1.0.4"
     path-key "^2.0.1"
@@ -1426,7 +1530,7 @@
     shebang-command "^1.2.0"
     which "^1.2.9"
 
-cross-spawn@^7.0.2, cross-spawn@^7.0.3:
+cross-spawn@^7.0.3:
   version "7.0.3"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
   integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@@ -1435,30 +1539,39 @@
     shebang-command "^2.0.0"
     which "^2.0.1"
 
-data-view-buffer@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2"
-  integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==
+cross-spawn@^7.0.6:
+  version "7.0.6"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
+  integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
   dependencies:
-    call-bind "^1.0.6"
-    es-errors "^1.3.0"
-    is-data-view "^1.0.1"
+    path-key "^3.1.0"
+    shebang-command "^2.0.0"
+    which "^2.0.1"
 
-data-view-byte-length@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2"
-  integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==
+data-view-buffer@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570"
+  integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==
   dependencies:
-    call-bind "^1.0.7"
+    call-bound "^1.0.3"
     es-errors "^1.3.0"
-    is-data-view "^1.0.1"
+    is-data-view "^1.0.2"
 
-data-view-byte-offset@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a"
-  integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==
+data-view-byte-length@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735"
+  integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==
   dependencies:
-    call-bind "^1.0.6"
+    call-bound "^1.0.3"
+    es-errors "^1.3.0"
+    is-data-view "^1.0.2"
+
+data-view-byte-offset@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191"
+  integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==
+  dependencies:
+    call-bound "^1.0.2"
     es-errors "^1.3.0"
     is-data-view "^1.0.1"
 
@@ -1481,17 +1594,31 @@
   dependencies:
     ms "^2.1.1"
 
-debug@^4.1.1, debug@^4.3.4:
+debug@^4.1.1, debug@^4.3.6:
+  version "4.4.1"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
+  integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
+  dependencies:
+    ms "^2.1.3"
+
+debug@^4.3.1, debug@^4.3.2:
+  version "4.3.7"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
+  integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
+  dependencies:
+    ms "^2.1.3"
+
+debug@^4.3.4:
   version "4.3.4"
   resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
   integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
   dependencies:
     ms "2.1.2"
 
-debug@^4.3.1, debug@^4.3.2:
-  version "4.3.7"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
-  integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
+debug@^4.3.5, debug@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
+  integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
   dependencies:
     ms "^2.1.3"
 
@@ -1528,6 +1655,13 @@
   resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
   integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
 
+default-gateway@^6.0.0:
+  version "6.0.3"
+  resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71"
+  integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==
+  dependencies:
+    execa "^5.0.0"
+
 define-data-property@^1.0.1, define-data-property@^1.1.4:
   version "1.1.4"
   resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
@@ -1542,7 +1676,7 @@
   resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f"
   integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==
 
-define-properties@^1.2.0, define-properties@^1.2.1:
+define-properties@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c"
   integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==
@@ -1578,7 +1712,7 @@
   resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
   integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
 
-depd@^2.0.0, depd@~2.0.0:
+depd@2.0.0, depd@^2.0.0, depd@~2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
   integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
@@ -1602,13 +1736,6 @@
     leven "^3.1.0"
     lodash.deburr "^4.1.0"
 
-dir-glob@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
-  integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
-  dependencies:
-    path-type "^4.0.0"
-
 doctrine@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
@@ -1616,13 +1743,6 @@
   dependencies:
     esutils "^2.0.2"
 
-doctrine@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
-  integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
-  dependencies:
-    esutils "^2.0.2"
-
 dom-serializer@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
@@ -1644,15 +1764,24 @@
   dependencies:
     domelementtype "^2.3.0"
 
-domutils@^3.0.1:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e"
-  integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
+domutils@^3.1.0:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.2.2.tgz#edbfe2b668b0c1d97c24baf0f1062b132221bc78"
+  integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==
   dependencies:
     dom-serializer "^2.0.0"
     domelementtype "^2.3.0"
     domhandler "^5.0.3"
 
+dunder-proto@^1.0.0, dunder-proto@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
+  integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
+  dependencies:
+    call-bind-apply-helpers "^1.0.1"
+    es-errors "^1.3.0"
+    gopd "^1.2.0"
+
 ee-first@1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -1668,7 +1797,20 @@
   resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
   integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
 
-entities@^4.2.0, entities@^4.4.0:
+encodeurl@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
+  integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
+
+enhanced-resolve@^5.17.1:
+  version "5.18.1"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz#728ab082f8b7b6836de51f1637aab5d3b9568faf"
+  integrity sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==
+  dependencies:
+    graceful-fs "^4.2.4"
+    tapable "^2.2.0"
+
+entities@^4.2.0, entities@^4.5.0:
   version "4.5.0"
   resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
   integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
@@ -1680,74 +1822,77 @@
   dependencies:
     is-arrayish "^0.2.1"
 
-es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2:
-  version "1.23.3"
-  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0"
-  integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==
+es-abstract@^1.23.2, es-abstract@^1.23.5, es-abstract@^1.23.9:
+  version "1.23.9"
+  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.9.tgz#5b45994b7de78dada5c1bebf1379646b32b9d606"
+  integrity sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==
   dependencies:
-    array-buffer-byte-length "^1.0.1"
-    arraybuffer.prototype.slice "^1.0.3"
+    array-buffer-byte-length "^1.0.2"
+    arraybuffer.prototype.slice "^1.0.4"
     available-typed-arrays "^1.0.7"
-    call-bind "^1.0.7"
-    data-view-buffer "^1.0.1"
-    data-view-byte-length "^1.0.1"
-    data-view-byte-offset "^1.0.0"
-    es-define-property "^1.0.0"
+    call-bind "^1.0.8"
+    call-bound "^1.0.3"
+    data-view-buffer "^1.0.2"
+    data-view-byte-length "^1.0.2"
+    data-view-byte-offset "^1.0.1"
+    es-define-property "^1.0.1"
     es-errors "^1.3.0"
     es-object-atoms "^1.0.0"
-    es-set-tostringtag "^2.0.3"
-    es-to-primitive "^1.2.1"
-    function.prototype.name "^1.1.6"
-    get-intrinsic "^1.2.4"
-    get-symbol-description "^1.0.2"
-    globalthis "^1.0.3"
-    gopd "^1.0.1"
+    es-set-tostringtag "^2.1.0"
+    es-to-primitive "^1.3.0"
+    function.prototype.name "^1.1.8"
+    get-intrinsic "^1.2.7"
+    get-proto "^1.0.0"
+    get-symbol-description "^1.1.0"
+    globalthis "^1.0.4"
+    gopd "^1.2.0"
     has-property-descriptors "^1.0.2"
-    has-proto "^1.0.3"
-    has-symbols "^1.0.3"
+    has-proto "^1.2.0"
+    has-symbols "^1.1.0"
     hasown "^2.0.2"
-    internal-slot "^1.0.7"
-    is-array-buffer "^3.0.4"
+    internal-slot "^1.1.0"
+    is-array-buffer "^3.0.5"
     is-callable "^1.2.7"
-    is-data-view "^1.0.1"
-    is-negative-zero "^2.0.3"
-    is-regex "^1.1.4"
-    is-shared-array-buffer "^1.0.3"
-    is-string "^1.0.7"
-    is-typed-array "^1.1.13"
-    is-weakref "^1.0.2"
-    object-inspect "^1.13.1"
+    is-data-view "^1.0.2"
+    is-regex "^1.2.1"
+    is-shared-array-buffer "^1.0.4"
+    is-string "^1.1.1"
+    is-typed-array "^1.1.15"
+    is-weakref "^1.1.0"
+    math-intrinsics "^1.1.0"
+    object-inspect "^1.13.3"
     object-keys "^1.1.1"
-    object.assign "^4.1.5"
-    regexp.prototype.flags "^1.5.2"
-    safe-array-concat "^1.1.2"
-    safe-regex-test "^1.0.3"
-    string.prototype.trim "^1.2.9"
-    string.prototype.trimend "^1.0.8"
+    object.assign "^4.1.7"
+    own-keys "^1.0.1"
+    regexp.prototype.flags "^1.5.3"
+    safe-array-concat "^1.1.3"
+    safe-push-apply "^1.0.0"
+    safe-regex-test "^1.1.0"
+    set-proto "^1.0.0"
+    string.prototype.trim "^1.2.10"
+    string.prototype.trimend "^1.0.9"
     string.prototype.trimstart "^1.0.8"
-    typed-array-buffer "^1.0.2"
-    typed-array-byte-length "^1.0.1"
-    typed-array-byte-offset "^1.0.2"
-    typed-array-length "^1.0.6"
-    unbox-primitive "^1.0.2"
-    which-typed-array "^1.1.15"
+    typed-array-buffer "^1.0.3"
+    typed-array-byte-length "^1.0.3"
+    typed-array-byte-offset "^1.0.4"
+    typed-array-length "^1.0.7"
+    unbox-primitive "^1.1.0"
+    which-typed-array "^1.1.18"
 
-es-define-property@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
-  integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
-  dependencies:
-    get-intrinsic "^1.2.4"
+es-define-property@^1.0.0, es-define-property@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
+  integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
 
-es-errors@^1.2.1, es-errors@^1.3.0:
+es-errors@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
   integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
 
 es-module-lexer@^1.0.0:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5"
-  integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a"
+  integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==
 
 es-object-atoms@^1.0.0:
   version "1.0.0"
@@ -1756,58 +1901,69 @@
   dependencies:
     es-errors "^1.3.0"
 
-es-set-tostringtag@^2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777"
-  integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==
+es-object-atoms@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
+  integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
   dependencies:
-    get-intrinsic "^1.2.4"
+    es-errors "^1.3.0"
+
+es-set-tostringtag@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d"
+  integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==
+  dependencies:
+    es-errors "^1.3.0"
+    get-intrinsic "^1.2.6"
     has-tostringtag "^1.0.2"
-    hasown "^2.0.1"
+    hasown "^2.0.2"
 
-es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763"
-  integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==
+es-shim-unscopables@^1.0.2, es-shim-unscopables@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz#438df35520dac5d105f3943d927549ea3b00f4b5"
+  integrity sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==
   dependencies:
-    hasown "^2.0.0"
+    hasown "^2.0.2"
 
-es-to-primitive@^1.2.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
-  integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
+es-to-primitive@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18"
+  integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==
   dependencies:
-    is-callable "^1.1.4"
-    is-date-object "^1.0.1"
-    is-symbol "^1.0.2"
+    is-callable "^1.2.7"
+    is-date-object "^1.0.5"
+    is-symbol "^1.0.4"
 
-"esbuild@^0.16 || ^0.17":
-  version "0.17.19"
-  resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.19.tgz#087a727e98299f0462a3d0bcdd9cd7ff100bd955"
-  integrity sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==
+esbuild@^0.25.0:
+  version "0.25.4"
+  resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.4.tgz#bb9a16334d4ef2c33c7301a924b8b863351a0854"
+  integrity sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==
   optionalDependencies:
-    "@esbuild/android-arm" "0.17.19"
-    "@esbuild/android-arm64" "0.17.19"
-    "@esbuild/android-x64" "0.17.19"
-    "@esbuild/darwin-arm64" "0.17.19"
-    "@esbuild/darwin-x64" "0.17.19"
-    "@esbuild/freebsd-arm64" "0.17.19"
-    "@esbuild/freebsd-x64" "0.17.19"
-    "@esbuild/linux-arm" "0.17.19"
-    "@esbuild/linux-arm64" "0.17.19"
-    "@esbuild/linux-ia32" "0.17.19"
-    "@esbuild/linux-loong64" "0.17.19"
-    "@esbuild/linux-mips64el" "0.17.19"
-    "@esbuild/linux-ppc64" "0.17.19"
-    "@esbuild/linux-riscv64" "0.17.19"
-    "@esbuild/linux-s390x" "0.17.19"
-    "@esbuild/linux-x64" "0.17.19"
-    "@esbuild/netbsd-x64" "0.17.19"
-    "@esbuild/openbsd-x64" "0.17.19"
-    "@esbuild/sunos-x64" "0.17.19"
-    "@esbuild/win32-arm64" "0.17.19"
-    "@esbuild/win32-ia32" "0.17.19"
-    "@esbuild/win32-x64" "0.17.19"
+    "@esbuild/aix-ppc64" "0.25.4"
+    "@esbuild/android-arm" "0.25.4"
+    "@esbuild/android-arm64" "0.25.4"
+    "@esbuild/android-x64" "0.25.4"
+    "@esbuild/darwin-arm64" "0.25.4"
+    "@esbuild/darwin-x64" "0.25.4"
+    "@esbuild/freebsd-arm64" "0.25.4"
+    "@esbuild/freebsd-x64" "0.25.4"
+    "@esbuild/linux-arm" "0.25.4"
+    "@esbuild/linux-arm64" "0.25.4"
+    "@esbuild/linux-ia32" "0.25.4"
+    "@esbuild/linux-loong64" "0.25.4"
+    "@esbuild/linux-mips64el" "0.25.4"
+    "@esbuild/linux-ppc64" "0.25.4"
+    "@esbuild/linux-riscv64" "0.25.4"
+    "@esbuild/linux-s390x" "0.25.4"
+    "@esbuild/linux-x64" "0.25.4"
+    "@esbuild/netbsd-arm64" "0.25.4"
+    "@esbuild/netbsd-x64" "0.25.4"
+    "@esbuild/openbsd-arm64" "0.25.4"
+    "@esbuild/openbsd-x64" "0.25.4"
+    "@esbuild/sunos-x64" "0.25.4"
+    "@esbuild/win32-arm64" "0.25.4"
+    "@esbuild/win32-ia32" "0.25.4"
+    "@esbuild/win32-x64" "0.25.4"
 
 escape-html@^1.0.3:
   version "1.0.3"
@@ -1824,15 +1980,22 @@
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
   integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
 
+eslint-compat-utils@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz#7fc92b776d185a70c4070d03fd26fde3d59652e4"
+  integrity sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==
+  dependencies:
+    semver "^7.5.4"
+
 eslint-config-google@^0.14.0:
   version "0.14.0"
   resolved "https://registry.yarnpkg.com/eslint-config-google/-/eslint-config-google-0.14.0.tgz#4f5f8759ba6e11b424294a219dbfa18c508bcc1a"
   integrity sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==
 
-eslint-config-prettier@^7.0.0:
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz#f4a4bd2832e810e8cc7c1411ec85b3e85c0c53f9"
-  integrity sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==
+eslint-config-prettier@9.1.0:
+  version "9.1.0"
+  resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f"
+  integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==
 
 eslint-import-resolver-node@^0.3.9:
   version "0.3.9"
@@ -1850,20 +2013,29 @@
   dependencies:
     debug "^3.2.7"
 
-eslint-plugin-es@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893"
-  integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==
+eslint-plugin-es-x@^7.8.0:
+  version "7.8.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz#a207aa08da37a7923f2a9599e6d3eb73f3f92b74"
+  integrity sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==
+  dependencies:
+    "@eslint-community/eslint-utils" "^4.1.2"
+    "@eslint-community/regexpp" "^4.11.0"
+    eslint-compat-utils "^0.5.1"
+
+eslint-plugin-es@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz#f0822f0c18a535a97c3e714e89f88586a7641ec9"
+  integrity sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==
   dependencies:
     eslint-utils "^2.0.0"
     regexpp "^3.0.0"
 
-eslint-plugin-html@^7.1.0:
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-7.1.0.tgz#aec2a3772b40ccf51a5be4f972f07600539d3b3e"
-  integrity sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==
+eslint-plugin-html@^8.1.2:
+  version "8.1.2"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-8.1.2.tgz#3a7a092d1e19e7e494014ed0747c5873856d7e1c"
+  integrity sha512-pbRchDV2SmqbCi/Ev/q3aAikzG9BcFe0IjjqjtMn8eTLq71ZUggyJB6CDmuwGAXmYZHrXI12XTfCqvgcnPRqGw==
   dependencies:
-    htmlparser2 "^8.0.1"
+    htmlparser2 "^9.1.0"
 
 eslint-plugin-import@^2.31.0:
   version "2.31.0"
@@ -1890,19 +2062,21 @@
     string.prototype.trimend "^1.0.8"
     tsconfig-paths "^3.15.0"
 
-eslint-plugin-jsdoc@^44.2.7:
-  version "44.2.7"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-44.2.7.tgz#5ecdb46ddfca209ecd58fff972a4eb74b8dde599"
-  integrity sha512-PcAJO7Wh4xIHPT+StBRpEbWgwCpIrYk75zL31RMbduVVHpgiy3Y8aXQ6pdbRJOq0fxHuepWSEAve8ZrPWTSKRg==
+eslint-plugin-jsdoc@^50.6.11:
+  version "50.6.17"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.6.17.tgz#68a1f1e91aeac8f2784c7e9ee4229f31adb773b2"
+  integrity sha512-hq+VQylhd12l8qjexyriDsejZhqiP33WgMTy2AmaGZ9+MrMWVqPECsM87GPxgHfQn0zw+YTuhqjUfk1f+q67aQ==
   dependencies:
-    "@es-joy/jsdoccomment" "~0.39.4"
+    "@es-joy/jsdoccomment" "~0.50.1"
     are-docs-informative "^0.0.2"
-    comment-parser "1.3.1"
-    debug "^4.3.4"
+    comment-parser "1.4.1"
+    debug "^4.3.6"
     escape-string-regexp "^4.0.0"
-    esquery "^1.5.0"
-    semver "^7.5.1"
-    spdx-expression-parse "^3.0.1"
+    espree "^10.1.0"
+    esquery "^1.6.0"
+    parse-imports-exports "^0.2.4"
+    semver "^7.6.3"
+    spdx-expression-parse "^4.0.0"
 
 eslint-plugin-lit@^1.15.0:
   version "1.15.0"
@@ -1913,49 +2087,59 @@
     parse5-htmlparser2-tree-adapter "^6.0.1"
     requireindex "^1.2.0"
 
-eslint-plugin-node@^11.1.0:
-  version "11.1.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d"
-  integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==
+eslint-plugin-n@15.7.0:
+  version "15.7.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz#e29221d8f5174f84d18f2eb94765f2eeea033b90"
+  integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==
   dependencies:
-    eslint-plugin-es "^3.0.0"
-    eslint-utils "^2.0.0"
+    builtins "^5.0.1"
+    eslint-plugin-es "^4.1.0"
+    eslint-utils "^3.0.0"
     ignore "^5.1.1"
-    minimatch "^3.0.4"
-    resolve "^1.10.1"
-    semver "^6.1.0"
+    is-core-module "^2.11.0"
+    minimatch "^3.1.2"
+    resolve "^1.22.1"
+    semver "^7.3.8"
 
-eslint-plugin-prettier@^3.1.4:
-  version "3.4.1"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5"
-  integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==
+eslint-plugin-n@^17.17.0:
+  version "17.18.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-17.18.0.tgz#8515979b49ef8db7bb16e457b8ed22cc695d2a84"
+  integrity sha512-hvZ/HusueqTJ7VDLoCpjN0hx4N4+jHIWTXD4TMLHy9F23XkDagR9v+xQWRWR57yY55GPF8NnD4ox9iGTxirY8A==
+  dependencies:
+    "@eslint-community/eslint-utils" "^4.5.0"
+    enhanced-resolve "^5.17.1"
+    eslint-plugin-es-x "^7.8.0"
+    get-tsconfig "^4.8.1"
+    globals "^15.11.0"
+    ignore "^5.3.2"
+    minimatch "^9.0.5"
+    semver "^7.6.3"
+
+eslint-plugin-prettier@5.2.1:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz#d1c8f972d8f60e414c25465c163d16f209411f95"
+  integrity sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==
   dependencies:
     prettier-linter-helpers "^1.0.0"
+    synckit "^0.9.1"
 
-eslint-plugin-prettier@^4.2.1:
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b"
-  integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==
+eslint-plugin-prettier@^5.4.0:
+  version "5.4.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.0.tgz#54d4748904e58eaf1ffe26c4bffa4986ca7f952b"
+  integrity sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA==
   dependencies:
     prettier-linter-helpers "^1.0.0"
+    synckit "^0.11.0"
 
 eslint-plugin-regex@^1.10.0:
   version "1.10.0"
   resolved "https://registry.yarnpkg.com/eslint-plugin-regex/-/eslint-plugin-regex-1.10.0.tgz#d182cedbeb89eb03cd8e53f750f6f92e14fa6f9c"
   integrity sha512-C8/qYKkkbIb0epxKzaz4aw7oVAOmm19fJpR/moUrUToq/vc4xW4sEKMlTQqH6EtNGpvLjYsbbZRlWNWwQGeTSA==
 
-eslint-scope@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
-  integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
-  dependencies:
-    esrecurse "^4.3.0"
-    estraverse "^4.1.1"
-
-eslint-scope@^7.2.2:
-  version "7.2.2"
-  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
-  integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
+eslint-scope@^8.3.0:
+  version "8.3.0"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.3.0.tgz#10cd3a918ffdd722f5f3f7b5b83db9b23c87340d"
+  integrity sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==
   dependencies:
     esrecurse "^4.3.0"
     estraverse "^5.2.0"
@@ -1967,75 +2151,84 @@
   dependencies:
     eslint-visitor-keys "^1.1.0"
 
+eslint-utils@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
+  integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
+  dependencies:
+    eslint-visitor-keys "^2.0.0"
+
 eslint-visitor-keys@^1.1.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
   integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
 
-eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
+eslint-visitor-keys@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
+  integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
+
+eslint-visitor-keys@^3.4.3:
   version "3.4.3"
   resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
   integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
 
-eslint@^7.10.0, eslint@^8.57.1:
-  version "8.57.1"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9"
-  integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
+eslint-visitor-keys@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
+  integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
+
+eslint@8.57.1, eslint@^9.26.0:
+  version "9.26.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.26.0.tgz#978fe029adc2aceed28ab437bca876e83461c3b4"
+  integrity sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==
   dependencies:
     "@eslint-community/eslint-utils" "^4.2.0"
-    "@eslint-community/regexpp" "^4.6.1"
-    "@eslint/eslintrc" "^2.1.4"
-    "@eslint/js" "8.57.1"
-    "@humanwhocodes/config-array" "^0.13.0"
+    "@eslint-community/regexpp" "^4.12.1"
+    "@eslint/config-array" "^0.20.0"
+    "@eslint/config-helpers" "^0.2.1"
+    "@eslint/core" "^0.13.0"
+    "@eslint/eslintrc" "^3.3.1"
+    "@eslint/js" "9.26.0"
+    "@eslint/plugin-kit" "^0.2.8"
+    "@humanfs/node" "^0.16.6"
     "@humanwhocodes/module-importer" "^1.0.1"
-    "@nodelib/fs.walk" "^1.2.8"
-    "@ungap/structured-clone" "^1.2.0"
+    "@humanwhocodes/retry" "^0.4.2"
+    "@modelcontextprotocol/sdk" "^1.8.0"
+    "@types/estree" "^1.0.6"
+    "@types/json-schema" "^7.0.15"
     ajv "^6.12.4"
     chalk "^4.0.0"
-    cross-spawn "^7.0.2"
+    cross-spawn "^7.0.6"
     debug "^4.3.2"
-    doctrine "^3.0.0"
     escape-string-regexp "^4.0.0"
-    eslint-scope "^7.2.2"
-    eslint-visitor-keys "^3.4.3"
-    espree "^9.6.1"
-    esquery "^1.4.2"
+    eslint-scope "^8.3.0"
+    eslint-visitor-keys "^4.2.0"
+    espree "^10.3.0"
+    esquery "^1.5.0"
     esutils "^2.0.2"
     fast-deep-equal "^3.1.3"
-    file-entry-cache "^6.0.1"
+    file-entry-cache "^8.0.0"
     find-up "^5.0.0"
     glob-parent "^6.0.2"
-    globals "^13.19.0"
-    graphemer "^1.4.0"
     ignore "^5.2.0"
     imurmurhash "^0.1.4"
     is-glob "^4.0.0"
-    is-path-inside "^3.0.3"
-    js-yaml "^4.1.0"
     json-stable-stringify-without-jsonify "^1.0.1"
-    levn "^0.4.1"
     lodash.merge "^4.6.2"
     minimatch "^3.1.2"
     natural-compare "^1.4.0"
     optionator "^0.9.3"
-    strip-ansi "^6.0.1"
-    text-table "^0.2.0"
+    zod "^3.24.2"
 
-espree@^9.6.0, espree@^9.6.1:
-  version "9.6.1"
-  resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
-  integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
+espree@^10.0.1, espree@^10.1.0, espree@^10.3.0:
+  version "10.3.0"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a"
+  integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==
   dependencies:
-    acorn "^8.9.0"
+    acorn "^8.14.0"
     acorn-jsx "^5.3.2"
-    eslint-visitor-keys "^3.4.1"
-
-esquery@^1.4.2:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
-  integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
-  dependencies:
-    estraverse "^5.1.0"
+    eslint-visitor-keys "^4.2.0"
 
 esquery@^1.5.0:
   version "1.5.0"
@@ -2044,6 +2237,13 @@
   dependencies:
     estraverse "^5.1.0"
 
+esquery@^1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
+  integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
+  dependencies:
+    estraverse "^5.1.0"
+
 esrecurse@^4.3.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
@@ -2051,20 +2251,15 @@
   dependencies:
     estraverse "^5.2.0"
 
-estraverse@^4.1.1:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
-  integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
-
 estraverse@^5.1.0, estraverse@^5.2.0:
   version "5.3.0"
   resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
   integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
 
-estree-walker@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
-  integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
+estree-walker@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
+  integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
 
 esutils@^2.0.2:
   version "2.0.3"
@@ -2076,6 +2271,18 @@
   resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
   integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
 
+eventsource-parser@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.1.tgz#5e358dba9a55ba64ca90da883c4ca35bd82467bd"
+  integrity sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==
+
+eventsource@^3.0.2:
+  version "3.0.6"
+  resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-3.0.6.tgz#5c4b24cd70c0323eed2651a5ee07bd4bc391e656"
+  integrity sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==
+  dependencies:
+    eventsource-parser "^3.0.1"
+
 execa@^5.0.0:
   version "5.1.1"
   resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
@@ -2104,6 +2311,44 @@
     snapdragon "^0.8.1"
     to-regex "^3.0.1"
 
+express-rate-limit@^7.5.0:
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.5.0.tgz#6a67990a724b4fbbc69119419feef50c51e8b28f"
+  integrity sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==
+
+express@^5.0.1:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/express/-/express-5.1.0.tgz#d31beaf715a0016f0d53f47d3b4d7acf28c75cc9"
+  integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==
+  dependencies:
+    accepts "^2.0.0"
+    body-parser "^2.2.0"
+    content-disposition "^1.0.0"
+    content-type "^1.0.5"
+    cookie "^0.7.1"
+    cookie-signature "^1.2.1"
+    debug "^4.4.0"
+    encodeurl "^2.0.0"
+    escape-html "^1.0.3"
+    etag "^1.8.1"
+    finalhandler "^2.1.0"
+    fresh "^2.0.0"
+    http-errors "^2.0.0"
+    merge-descriptors "^2.0.0"
+    mime-types "^3.0.0"
+    on-finished "^2.4.1"
+    once "^1.4.0"
+    parseurl "^1.3.3"
+    proxy-addr "^2.0.7"
+    qs "^6.14.0"
+    range-parser "^1.2.1"
+    router "^2.2.0"
+    send "^1.1.0"
+    serve-static "^2.2.0"
+    statuses "^2.0.1"
+    type-is "^2.0.1"
+    vary "^1.1.2"
+
 extend-shallow@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
@@ -2164,16 +2409,16 @@
     merge2 "^1.2.3"
     micromatch "^3.1.10"
 
-fast-glob@^3.2.2, fast-glob@^3.2.9:
-  version "3.3.2"
-  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
-  integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+fast-glob@^3.2.2, fast-glob@^3.3.2:
+  version "3.3.3"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
+  integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==
   dependencies:
     "@nodelib/fs.stat" "^2.0.2"
     "@nodelib/fs.walk" "^1.2.3"
     glob-parent "^5.1.2"
     merge2 "^1.3.0"
-    micromatch "^4.0.4"
+    micromatch "^4.0.8"
 
 fast-json-stable-stringify@^2.0.0:
   version "2.1.0"
@@ -2199,12 +2444,12 @@
   dependencies:
     escape-string-regexp "^1.0.5"
 
-file-entry-cache@^6.0.1:
-  version "6.0.1"
-  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
-  integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
+file-entry-cache@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f"
+  integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==
   dependencies:
-    flat-cache "^3.0.4"
+    flat-cache "^4.0.0"
 
 fill-range@^4.0.0:
   version "4.0.0"
@@ -2216,13 +2461,25 @@
     repeat-string "^1.6.1"
     to-regex-range "^2.1.0"
 
-fill-range@^7.0.1:
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
-  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+fill-range@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+  integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
   dependencies:
     to-regex-range "^5.0.1"
 
+finalhandler@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-2.1.0.tgz#72306373aa89d05a8242ed569ed86a1bff7c561f"
+  integrity sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==
+  dependencies:
+    debug "^4.4.0"
+    encodeurl "^2.0.0"
+    escape-html "^1.0.3"
+    on-finished "^2.4.1"
+    parseurl "^1.3.3"
+    statuses "^2.0.1"
+
 find-replace@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38"
@@ -2246,32 +2503,36 @@
     locate-path "^6.0.0"
     path-exists "^4.0.0"
 
-flat-cache@^3.0.4:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee"
-  integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==
+flat-cache@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c"
+  integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==
   dependencies:
     flatted "^3.2.9"
-    keyv "^4.5.3"
-    rimraf "^3.0.2"
+    keyv "^4.5.4"
 
 flatted@^3.2.9:
   version "3.3.1"
   resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
   integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
 
-for-each@^0.3.3:
-  version "0.3.3"
-  resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
-  integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
+for-each@^0.3.3, for-each@^0.3.5:
+  version "0.3.5"
+  resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47"
+  integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==
   dependencies:
-    is-callable "^1.1.3"
+    is-callable "^1.2.7"
 
 for-in@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
   integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==
 
+forwarded@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
+  integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+
 fragment-cache@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
@@ -2279,6 +2540,11 @@
   dependencies:
     map-cache "^0.2.2"
 
+fresh@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4"
+  integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==
+
 fresh@~0.5.2:
   version "0.5.2"
   resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@@ -2299,15 +2565,17 @@
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
   integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
 
-function.prototype.name@^1.1.6:
-  version "1.1.6"
-  resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd"
-  integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==
+function.prototype.name@^1.1.6, function.prototype.name@^1.1.8:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78"
+  integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==
   dependencies:
-    call-bind "^1.0.2"
-    define-properties "^1.2.0"
-    es-abstract "^1.22.1"
+    call-bind "^1.0.8"
+    call-bound "^1.0.3"
+    define-properties "^1.2.1"
     functions-have-names "^1.2.3"
+    hasown "^2.0.2"
+    is-callable "^1.2.7"
 
 functions-have-names@^1.2.3:
   version "1.2.3"
@@ -2319,30 +2587,50 @@
   resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
   integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
 
-get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
-  version "1.2.4"
-  resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
-  integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
+get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
+  integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
   dependencies:
+    call-bind-apply-helpers "^1.0.2"
+    es-define-property "^1.0.1"
     es-errors "^1.3.0"
+    es-object-atoms "^1.1.1"
     function-bind "^1.1.2"
-    has-proto "^1.0.1"
-    has-symbols "^1.0.3"
-    hasown "^2.0.0"
+    get-proto "^1.0.1"
+    gopd "^1.2.0"
+    has-symbols "^1.1.0"
+    hasown "^2.0.2"
+    math-intrinsics "^1.1.0"
+
+get-proto@^1.0.0, get-proto@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
+  integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
+  dependencies:
+    dunder-proto "^1.0.1"
+    es-object-atoms "^1.0.0"
 
 get-stream@^6.0.0:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
   integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
 
-get-symbol-description@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5"
-  integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==
+get-symbol-description@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee"
+  integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==
   dependencies:
-    call-bind "^1.0.5"
+    call-bound "^1.0.3"
     es-errors "^1.3.0"
-    get-intrinsic "^1.2.4"
+    get-intrinsic "^1.2.6"
+
+get-tsconfig@^4.8.1:
+  version "4.10.0"
+  resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.10.0.tgz#403a682b373a823612475a4c2928c7326fc0f6bb"
+  integrity sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==
+  dependencies:
+    resolve-pkg-maps "^1.0.0"
 
 get-value@^2.0.3, get-value@^2.0.6:
   version "2.0.6"
@@ -2357,7 +2645,7 @@
     is-glob "^3.1.0"
     path-dirname "^1.0.0"
 
-glob-parent@^5.1.2, glob-parent@~5.1.2:
+glob-parent@^5.1.2:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
   integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
@@ -2388,14 +2676,17 @@
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-globals@^13.19.0:
-  version "13.24.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171"
-  integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==
-  dependencies:
-    type-fest "^0.20.2"
+globals@^14.0.0:
+  version "14.0.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
+  integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
 
-globalthis@^1.0.3:
+globals@^15.11.0:
+  version "15.15.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8"
+  integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==
+
+globalthis@^1.0.4:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236"
   integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==
@@ -2403,31 +2694,17 @@
     define-properties "^1.2.1"
     gopd "^1.0.1"
 
-globby@^11.1.0:
-  version "11.1.0"
-  resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
-  integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
-  dependencies:
-    array-union "^2.1.0"
-    dir-glob "^3.0.1"
-    fast-glob "^3.2.9"
-    ignore "^5.2.0"
-    merge2 "^1.4.1"
-    slash "^3.0.0"
-
 google-protobuf@^3.6.1:
   version "3.21.2"
   resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
   integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==
 
-gopd@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
-  integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
-  dependencies:
-    get-intrinsic "^1.1.3"
+gopd@^1.0.1, gopd@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
+  integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
 
-graceful-fs@^4.1.2:
+graceful-fs@^4.1.2, graceful-fs@^4.2.4:
   version "4.2.11"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
   integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
@@ -2437,36 +2714,36 @@
   resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
   integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
 
-gts@^3.1.1:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/gts/-/gts-3.1.1.tgz#c7347cf8f8ea32577909659b22bf698ac5ca8082"
-  integrity sha512-Jw44aBbzMnd1vtZs7tZt3LMstKQukCBg7N4CKVGzviIQ45Cz5b9lxDJGXVKj/9ySuGv6TYEeijZJGbiiVcM27w==
+gts@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/gts/-/gts-6.0.2.tgz#f7ff83fd786de92384740da4409f954261a0a62c"
+  integrity sha512-lp9+eDzzm6TYqiBpgGY00EInxBHFTJiU5brsVp11qXCJEw7Q6WNNngja0spZeqSFWSquaRuHQUuWxdZLaxnKmw==
   dependencies:
-    "@typescript-eslint/eslint-plugin" "^4.2.0"
-    "@typescript-eslint/parser" "^4.2.0"
-    chalk "^4.1.0"
-    eslint "^7.10.0"
-    eslint-config-prettier "^7.0.0"
-    eslint-plugin-node "^11.1.0"
-    eslint-plugin-prettier "^3.1.4"
+    "@typescript-eslint/eslint-plugin" "5.62.0"
+    "@typescript-eslint/parser" "5.62.0"
+    chalk "^4.1.2"
+    eslint "8.57.1"
+    eslint-config-prettier "9.1.0"
+    eslint-plugin-n "15.7.0"
+    eslint-plugin-prettier "5.2.1"
     execa "^5.0.0"
     inquirer "^7.3.3"
     json5 "^2.1.3"
     meow "^9.0.0"
     ncp "^2.0.0"
-    prettier "^2.1.2"
-    rimraf "^3.0.2"
-    write-file-atomic "^3.0.3"
+    prettier "3.3.3"
+    rimraf "3.0.2"
+    write-file-atomic "^4.0.0"
 
 hard-rejection@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
   integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==
 
-has-bigints@^1.0.1, has-bigints@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
-  integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
+has-bigints@^1.0.2:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe"
+  integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==
 
 has-flag@^3.0.0:
   version "3.0.0"
@@ -2485,17 +2762,19 @@
   dependencies:
     es-define-property "^1.0.0"
 
-has-proto@^1.0.1, has-proto@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
-  integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
+has-proto@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5"
+  integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==
+  dependencies:
+    dunder-proto "^1.0.0"
 
-has-symbols@^1.0.2, has-symbols@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
-  integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+has-symbols@^1.0.3, has-symbols@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
+  integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
 
-has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
+has-tostringtag@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
   integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
@@ -2533,7 +2812,7 @@
     is-number "^3.0.0"
     kind-of "^4.0.0"
 
-hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2:
+hasown@^2.0.0, hasown@^2.0.2:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
   integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
@@ -2552,15 +2831,15 @@
   dependencies:
     lru-cache "^6.0.0"
 
-htmlparser2@^8.0.1:
-  version "8.0.2"
-  resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
-  integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
+htmlparser2@^9.1.0:
+  version "9.1.0"
+  resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-9.1.0.tgz#cdb498d8a75a51f739b61d3f718136c369bc8c23"
+  integrity sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==
   dependencies:
     domelementtype "^2.3.0"
     domhandler "^5.0.3"
-    domutils "^3.0.1"
-    entities "^4.4.0"
+    domutils "^3.1.0"
+    entities "^4.5.0"
 
 http-assert@^1.3.0:
   version "1.5.0"
@@ -2570,6 +2849,17 @@
     deep-equal "~1.0.1"
     http-errors "~1.8.0"
 
+http-errors@2.0.0, http-errors@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+  integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+  dependencies:
+    depd "2.0.0"
+    inherits "2.0.4"
+    setprototypeof "1.2.0"
+    statuses "2.0.1"
+    toidentifier "1.0.1"
+
 http-errors@^1.6.3, http-errors@^1.7.3, http-errors@~1.8.0:
   version "1.8.1"
   resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
@@ -2596,6 +2886,13 @@
   resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
   integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
 
+iconv-lite@0.6.3, iconv-lite@^0.6.3:
+  version "0.6.3"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
+  integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
+  dependencies:
+    safer-buffer ">= 2.1.2 < 3.0.0"
+
 iconv-lite@^0.4.24:
   version "0.4.24"
   resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -2603,12 +2900,7 @@
   dependencies:
     safer-buffer ">= 2.1.2 < 3"
 
-ignore@^5.1.1:
-  version "5.3.0"
-  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78"
-  integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==
-
-ignore@^5.2.0:
+ignore@^5.1.1, ignore@^5.2.0, ignore@^5.3.1, ignore@^5.3.2:
   version "5.3.2"
   resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
   integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
@@ -2668,19 +2960,34 @@
     strip-ansi "^6.0.0"
     through "^2.3.6"
 
-internal-slot@^1.0.7:
-  version "1.0.7"
-  resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802"
-  integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==
+internal-ip@^6.2.0:
+  version "6.2.0"
+  resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-6.2.0.tgz#d5541e79716e406b74ac6b07b856ef18dc1621c1"
+  integrity sha512-D8WGsR6yDt8uq7vDMu7mjcR+yRMm3dW8yufyChmszWRjcSHuxLBkR3GdS2HZAjodsaGuCvXeEJpueisXJULghg==
+  dependencies:
+    default-gateway "^6.0.0"
+    ipaddr.js "^1.9.1"
+    is-ip "^3.1.0"
+    p-event "^4.2.0"
+
+internal-slot@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961"
+  integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==
   dependencies:
     es-errors "^1.3.0"
-    hasown "^2.0.0"
-    side-channel "^1.0.4"
+    hasown "^2.0.2"
+    side-channel "^1.1.0"
 
-ip@^1.1.5:
-  version "1.1.8"
-  resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48"
-  integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==
+ip-regex@^4.0.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5"
+  integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==
+
+ipaddr.js@1.9.1, ipaddr.js@^1.9.1:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+  integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
 
 is-accessor-descriptor@^1.0.1:
   version "1.0.1"
@@ -2689,72 +2996,63 @@
   dependencies:
     hasown "^2.0.0"
 
-is-array-buffer@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98"
-  integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==
+is-array-buffer@^3.0.4, is-array-buffer@^3.0.5:
+  version "3.0.5"
+  resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280"
+  integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==
   dependencies:
-    call-bind "^1.0.2"
-    get-intrinsic "^1.2.1"
+    call-bind "^1.0.8"
+    call-bound "^1.0.3"
+    get-intrinsic "^1.2.6"
 
 is-arrayish@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
   integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
 
-is-bigint@^1.0.1:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
-  integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
+is-async-function@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523"
+  integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==
   dependencies:
-    has-bigints "^1.0.1"
+    async-function "^1.0.0"
+    call-bound "^1.0.3"
+    get-proto "^1.0.1"
+    has-tostringtag "^1.0.2"
+    safe-regex-test "^1.1.0"
 
-is-binary-path@~2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
-  integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+is-bigint@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672"
+  integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==
   dependencies:
-    binary-extensions "^2.0.0"
+    has-bigints "^1.0.2"
 
-is-boolean-object@^1.1.0:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
-  integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
+is-boolean-object@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz#7067f47709809a393c71ff5bb3e135d8a9215d9e"
+  integrity sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==
   dependencies:
-    call-bind "^1.0.2"
-    has-tostringtag "^1.0.0"
+    call-bound "^1.0.3"
+    has-tostringtag "^1.0.2"
 
 is-buffer@^1.1.5:
   version "1.1.6"
   resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
   integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
 
-is-builtin-module@^3.1.0:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169"
-  integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==
-  dependencies:
-    builtin-modules "^3.3.0"
-
-is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
+is-callable@^1.2.7:
   version "1.2.7"
   resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
   integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
 
-is-core-module@^2.13.0, is-core-module@^2.15.1:
-  version "2.15.1"
-  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37"
-  integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==
+is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.15.1, is-core-module@^2.16.0, is-core-module@^2.5.0:
+  version "2.16.1"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4"
+  integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==
   dependencies:
     hasown "^2.0.2"
 
-is-core-module@^2.5.0:
-  version "2.13.1"
-  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
-  integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
-  dependencies:
-    hasown "^2.0.0"
-
 is-data-descriptor@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz#2109164426166d32ea38c405c1e0945d9e6a4eeb"
@@ -2762,19 +3060,22 @@
   dependencies:
     hasown "^2.0.0"
 
-is-data-view@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f"
-  integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==
+is-data-view@^1.0.1, is-data-view@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e"
+  integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==
   dependencies:
+    call-bound "^1.0.2"
+    get-intrinsic "^1.2.6"
     is-typed-array "^1.1.13"
 
-is-date-object@^1.0.1:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
-  integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
+is-date-object@^1.0.5, is-date-object@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7"
+  integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==
   dependencies:
-    has-tostringtag "^1.0.0"
+    call-bound "^1.0.2"
+    has-tostringtag "^1.0.2"
 
 is-descriptor@^0.1.0:
   version "0.1.7"
@@ -2814,17 +3115,27 @@
   resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
   integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
 
+is-finalizationregistry@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90"
+  integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==
+  dependencies:
+    call-bound "^1.0.3"
+
 is-fullwidth-code-point@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
   integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
 
-is-generator-function@^1.0.7:
-  version "1.0.10"
-  resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
-  integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
+is-generator-function@^1.0.10, is-generator-function@^1.0.7:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca"
+  integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==
   dependencies:
-    has-tostringtag "^1.0.0"
+    call-bound "^1.0.3"
+    get-proto "^1.0.0"
+    has-tostringtag "^1.0.2"
+    safe-regex-test "^1.1.0"
 
 is-glob@^3.1.0:
   version "3.1.0"
@@ -2833,29 +3144,37 @@
   dependencies:
     is-extglob "^2.1.0"
 
-is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
   integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
   dependencies:
     is-extglob "^2.1.1"
 
+is-ip@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8"
+  integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==
+  dependencies:
+    ip-regex "^4.0.0"
+
+is-map@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e"
+  integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==
+
 is-module@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
   integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==
 
-is-negative-zero@^2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747"
-  integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==
-
-is-number-object@^1.0.4:
-  version "1.0.7"
-  resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
-  integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==
+is-number-object@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541"
+  integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==
   dependencies:
-    has-tostringtag "^1.0.0"
+    call-bound "^1.0.3"
+    has-tostringtag "^1.0.2"
 
 is-number@^3.0.0:
   version "3.0.0"
@@ -2869,11 +3188,6 @@
   resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
   integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
 
-is-path-inside@^3.0.3:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
-  integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
-
 is-plain-obj@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
@@ -2886,58 +3200,81 @@
   dependencies:
     isobject "^3.0.1"
 
-is-regex@^1.1.4:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
-  integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
-  dependencies:
-    call-bind "^1.0.2"
-    has-tostringtag "^1.0.0"
+is-promise@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3"
+  integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==
 
-is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688"
-  integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==
+is-regex@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22"
+  integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==
   dependencies:
-    call-bind "^1.0.7"
+    call-bound "^1.0.2"
+    gopd "^1.2.0"
+    has-tostringtag "^1.0.2"
+    hasown "^2.0.2"
+
+is-set@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d"
+  integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==
+
+is-shared-array-buffer@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f"
+  integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==
+  dependencies:
+    call-bound "^1.0.3"
 
 is-stream@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
   integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
 
-is-string@^1.0.5, is-string@^1.0.7:
-  version "1.0.7"
-  resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
-  integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
+is-string@^1.0.7, is-string@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9"
+  integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==
   dependencies:
-    has-tostringtag "^1.0.0"
+    call-bound "^1.0.3"
+    has-tostringtag "^1.0.2"
 
-is-symbol@^1.0.2, is-symbol@^1.0.3:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
-  integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
+is-symbol@^1.0.4, is-symbol@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634"
+  integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==
   dependencies:
-    has-symbols "^1.0.2"
+    call-bound "^1.0.2"
+    has-symbols "^1.1.0"
+    safe-regex-test "^1.1.0"
 
-is-typed-array@^1.1.13:
-  version "1.1.13"
-  resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229"
-  integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==
+is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15:
+  version "1.1.15"
+  resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b"
+  integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==
   dependencies:
-    which-typed-array "^1.1.14"
+    which-typed-array "^1.1.16"
 
-is-typedarray@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
-  integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
+is-weakmap@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd"
+  integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==
 
-is-weakref@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
-  integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
+is-weakref@^1.0.2, is-weakref@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.1.tgz#eea430182be8d64174bd96bffbc46f21bf3f9293"
+  integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==
   dependencies:
-    call-bind "^1.0.2"
+    call-bound "^1.0.3"
+
+is-weakset@^2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca"
+  integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==
+  dependencies:
+    call-bound "^1.0.3"
+    get-intrinsic "^1.2.6"
 
 is-windows@^1.0.2:
   version "1.0.2"
@@ -2962,9 +3299,9 @@
   integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
 
 isbinaryfile@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-5.0.0.tgz#034b7e54989dab8986598cbcea41f66663c65234"
-  integrity sha512-UDdnyGvMajJUWCkib7Cei/dvyJrrvo4FIrsvSFWdPpXSUorzXrDJ0S+X5Q4ZlasfPjca4yqCNNsjbCeiy8FFeg==
+  version "5.0.4"
+  resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-5.0.4.tgz#2a2edefa76cafa66613fe4c1ea52f7f031017bdf"
+  integrity sha512-YKBKVkKhty7s8rxddb40oOkuP0NbaeXrQvLin6QMHL7Ypiy2RW9LwOVrVgZRyOrhQlayMd9t+D8yDy8MKFTSDQ==
 
 isexe@^2.0.0:
   version "2.0.0"
@@ -2995,10 +3332,10 @@
   dependencies:
     argparse "^2.0.1"
 
-jsdoc-type-pratt-parser@~4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114"
-  integrity sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==
+jsdoc-type-pratt-parser@~4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz#ff6b4a3f339c34a6c188cbf50a16087858d22113"
+  integrity sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==
 
 json-buffer@3.0.1:
   version "3.0.1"
@@ -3044,7 +3381,7 @@
   dependencies:
     tsscmp "1.0.6"
 
-keyv@^4.5.3:
+keyv@^4.5.4:
   version "4.5.4"
   resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
   integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
@@ -3108,9 +3445,9 @@
     koa-send "^5.0.0"
 
 koa@^2.13.0:
-  version "2.15.0"
-  resolved "https://registry.yarnpkg.com/koa/-/koa-2.15.0.tgz#d24ae1b0ff378bf12eb3df584ab4204e4c12ac2b"
-  integrity sha512-KEL/vU1knsoUvfP4MC4/GthpQrY/p6dzwaaGI6Rt4NQuFqkw3qrvsdYF5pz3wOfi7IGTvMPHC9aZIcUKYFNxsw==
+  version "2.16.1"
+  resolved "https://registry.yarnpkg.com/koa/-/koa-2.16.1.tgz#ba1aae04d8319d7dac4a17a0d289d7482501e194"
+  integrity sha512-umfX9d3iuSxTQP4pnzLOz0HKnPg0FaUUIKcye2lOiz3KPu1Y3M3xlz76dISdFPQs37P9eJz1wUpcTS6KDPn9fA==
   dependencies:
     accepts "^1.3.5"
     cache-content-type "^1.0.0"
@@ -3192,11 +3529,6 @@
   dependencies:
     p-locate "^5.0.0"
 
-lodash.assignwith@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz#127a97f02adc41751a954d24b0de17e100e038eb"
-  integrity sha512-ZznplvbvtjK2gMvnQ1BR/zqPFZmS6jbK4p+6Up4xcRYA7yMIwxHCfbTcrYxXKzzqLsQ05eJPVznEW3tuwV7k1g==
-
 lodash.camelcase@^4.3.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
@@ -3212,7 +3544,7 @@
   resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
   integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
 
-lodash@^4.17.14, lodash@^4.17.19:
+lodash@^4.17.19:
   version "4.17.21"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
   integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -3229,6 +3561,11 @@
   dependencies:
     yallist "^4.0.0"
 
+lru-cache@^8.0.4:
+  version "8.0.5"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-8.0.5.tgz#983fe337f3e176667f8e567cfcce7cb064ea214e"
+  integrity sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==
+
 map-cache@^0.2.2:
   version "0.2.2"
   resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
@@ -3251,11 +3588,21 @@
   dependencies:
     object-visit "^1.0.0"
 
+math-intrinsics@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
+  integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
+
 media-typer@0.3.0:
   version "0.3.0"
   resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
   integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
 
+media-typer@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561"
+  integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==
+
 memorystream@^0.3.1:
   version "0.3.1"
   resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
@@ -3279,12 +3626,17 @@
     type-fest "^0.18.0"
     yargs-parser "^20.2.3"
 
+merge-descriptors@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz#ea922f660635a2249ee565e0449f951e6b603808"
+  integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==
+
 merge-stream@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
   integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
 
-merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1:
+merge2@^1.2.3, merge2@^1.3.0:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
   integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
@@ -3308,12 +3660,12 @@
     snapdragon "^0.8.1"
     to-regex "^3.0.2"
 
-micromatch@^4.0.4:
-  version "4.0.5"
-  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
-  integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+micromatch@^4.0.8:
+  version "4.0.8"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
+  integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
   dependencies:
-    braces "^3.0.2"
+    braces "^3.0.3"
     picomatch "^2.3.1"
 
 mime-db@1.52.0:
@@ -3321,6 +3673,11 @@
   resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
   integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
 
+mime-db@^1.54.0:
+  version "1.54.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5"
+  integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
+
 mime-types@^2.1.18, mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34:
   version "2.1.35"
   resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
@@ -3328,6 +3685,13 @@
   dependencies:
     mime-db "1.52.0"
 
+mime-types@^3.0.0, mime-types@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce"
+  integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==
+  dependencies:
+    mime-db "^1.54.0"
+
 mimic-fn@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
@@ -3338,13 +3702,20 @@
   resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
   integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
 
-minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
   version "3.1.2"
   resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
   integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
   dependencies:
     brace-expansion "^1.1.7"
 
+minimatch@^9.0.4, minimatch@^9.0.5:
+  version "9.0.5"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
+  integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
+  dependencies:
+    brace-expansion "^2.0.1"
+
 minimist-options@4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
@@ -3367,13 +3738,6 @@
     for-in "^1.0.2"
     is-extendable "^1.0.1"
 
-mkdirp@^0.5.6:
-  version "0.5.6"
-  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
-  integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
-  dependencies:
-    minimist "^1.2.6"
-
 ms@2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -3416,11 +3780,6 @@
     snapdragon "^0.8.1"
     to-regex "^3.0.1"
 
-natural-compare-lite@^1.4.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
-  integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==
-
 natural-compare@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@@ -3436,6 +3795,11 @@
   resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
   integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
 
+negotiator@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a"
+  integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
+
 nice-try@^1.0.4:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
@@ -3461,11 +3825,6 @@
     semver "^7.3.4"
     validate-npm-package-license "^3.0.1"
 
-normalize-path@^3.0.0, normalize-path@~3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
-  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
-
 npm-run-all@^4.1.5:
   version "4.1.5"
   resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba"
@@ -3488,6 +3847,11 @@
   dependencies:
     path-key "^3.0.0"
 
+object-assign@^4:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+  integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
 object-copy@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
@@ -3497,10 +3861,10 @@
     define-property "^0.2.5"
     kind-of "^3.0.3"
 
-object-inspect@^1.13.1:
-  version "1.13.2"
-  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff"
-  integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==
+object-inspect@^1.13.3:
+  version "1.13.4"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213"
+  integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==
 
 object-keys@^1.1.1:
   version "1.1.1"
@@ -3514,14 +3878,16 @@
   dependencies:
     isobject "^3.0.0"
 
-object.assign@^4.1.5:
-  version "4.1.5"
-  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0"
-  integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==
+object.assign@^4.1.7:
+  version "4.1.7"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d"
+  integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==
   dependencies:
-    call-bind "^1.0.5"
+    call-bind "^1.0.8"
+    call-bound "^1.0.3"
     define-properties "^1.2.1"
-    has-symbols "^1.0.3"
+    es-object-atoms "^1.0.0"
+    has-symbols "^1.1.0"
     object-keys "^1.1.1"
 
 object.fromentries@^2.0.8:
@@ -3551,22 +3917,23 @@
     isobject "^3.0.1"
 
 object.values@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b"
-  integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216"
+  integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==
   dependencies:
-    call-bind "^1.0.7"
+    call-bind "^1.0.8"
+    call-bound "^1.0.3"
     define-properties "^1.2.1"
     es-object-atoms "^1.0.0"
 
-on-finished@^2.3.0:
+on-finished@^2.3.0, on-finished@^2.4.1:
   version "2.4.1"
   resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
   integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
   dependencies:
     ee-first "1.1.1"
 
-once@^1.3.0:
+once@^1.3.0, once@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
   integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
@@ -3611,6 +3978,27 @@
   resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
   integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
 
+own-keys@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358"
+  integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==
+  dependencies:
+    get-intrinsic "^1.2.6"
+    object-keys "^1.1.1"
+    safe-push-apply "^1.0.0"
+
+p-event@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5"
+  integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==
+  dependencies:
+    p-timeout "^3.1.0"
+
+p-finally@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+  integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
+
 p-limit@^2.2.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
@@ -3639,6 +4027,13 @@
   dependencies:
     p-limit "^3.0.2"
 
+p-timeout@^3.1.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
+  integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
+  dependencies:
+    p-finally "^1.0.0"
+
 p-try@^2.0.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
@@ -3651,6 +4046,13 @@
   dependencies:
     callsites "^3.0.0"
 
+parse-imports-exports@^0.2.4:
+  version "0.2.4"
+  resolved "https://registry.yarnpkg.com/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz#e3fb3b5e264cfb55c25b5dfcbe7f410f8dc4e7af"
+  integrity sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==
+  dependencies:
+    parse-statements "1.0.11"
+
 parse-json@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
@@ -3669,6 +4071,11 @@
     json-parse-even-better-errors "^2.3.0"
     lines-and-columns "^1.1.6"
 
+parse-statements@1.0.11:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/parse-statements/-/parse-statements-1.0.11.tgz#8787c5d383ae5746568571614be72b0689584344"
+  integrity sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==
+
 parse5-htmlparser2-tree-adapter@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
@@ -3686,7 +4093,7 @@
   resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
   integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
 
-parseurl@^1.3.2:
+parseurl@^1.3.2, parseurl@^1.3.3:
   version "1.3.3"
   resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
   integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
@@ -3726,6 +4133,11 @@
   resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
   integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
 
+path-to-regexp@^8.0.0:
+  version "8.2.0"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.2.0.tgz#73990cc29e57a3ff2a0d914095156df5db79e8b4"
+  integrity sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==
+
 path-type@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
@@ -3733,16 +4145,21 @@
   dependencies:
     pify "^3.0.0"
 
-path-type@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
-  integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+picocolors@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
+  integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
 
-picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1:
+picomatch@^2.2.2, picomatch@^2.3.1:
   version "2.3.1"
   resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
   integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
 
+picomatch@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab"
+  integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
+
 pidtree@^0.3.0:
   version "0.3.1"
   resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a"
@@ -3753,14 +4170,18 @@
   resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
   integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==
 
+pkce-challenge@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/pkce-challenge/-/pkce-challenge-5.0.0.tgz#c3a405cb49e272094a38e890a2b51da0228c4d97"
+  integrity sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==
+
 portfinder@^1.0.32:
-  version "1.0.32"
-  resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.32.tgz#2fe1b9e58389712429dc2bea5beb2146146c7f81"
-  integrity sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==
+  version "1.0.37"
+  resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.37.tgz#92b754ef89a11801c8efe4b0e5cd845b0064c212"
+  integrity sha512-yuGIEjDAYnnOex9ddMnKZEMFE0CcGo6zbfzDklkmT1m5z734ss6JMzN9rNB3+RR7iS+F10D4/BVIaXOyh8PQKw==
   dependencies:
-    async "^2.6.4"
-    debug "^3.2.7"
-    mkdirp "^0.5.6"
+    async "^3.2.6"
+    debug "^4.3.6"
 
 posix-character-classes@^0.1.0:
   version "0.1.1"
@@ -3768,9 +4189,9 @@
   integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==
 
 possible-typed-array-names@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
-  integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae"
+  integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==
 
 prelude-ls@^1.2.1:
   version "1.2.1"
@@ -3784,7 +4205,12 @@
   dependencies:
     fast-diff "^1.1.2"
 
-prettier@^2.1.2, prettier@^2.8.8:
+prettier@3.3.3:
+  version "3.3.3"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105"
+  integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==
+
+prettier@^2.8.8:
   version "2.8.8"
   resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
   integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
@@ -3808,11 +4234,26 @@
     "@types/node" "^10.1.0"
     long "^4.0.0"
 
-punycode@^2.1.0, punycode@^2.1.1:
+proxy-addr@^2.0.7:
+  version "2.0.7"
+  resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
+  integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
+  dependencies:
+    forwarded "0.2.0"
+    ipaddr.js "1.9.1"
+
+punycode@^2.1.0, punycode@^2.3.1:
   version "2.3.1"
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
   integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
 
+qs@^6.14.0:
+  version "6.14.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930"
+  integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==
+  dependencies:
+    side-channel "^1.1.0"
+
 queue-microtask@^1.2.2:
   version "1.2.3"
   resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
@@ -3823,6 +4264,21 @@
   resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
   integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
 
+range-parser@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+  integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.0.tgz#25b3476f07a51600619dae3fe82ddc28a36e5e0f"
+  integrity sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==
+  dependencies:
+    bytes "3.1.2"
+    http-errors "2.0.0"
+    iconv-lite "0.6.3"
+    unpipe "1.0.0"
+
 read-pkg-up@^7.0.1:
   version "7.0.1"
   resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
@@ -3851,12 +4307,10 @@
     parse-json "^5.0.0"
     type-fest "^0.6.0"
 
-readdirp@~3.6.0:
-  version "3.6.0"
-  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
-  integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
-  dependencies:
-    picomatch "^2.2.1"
+readdirp@^4.0.1:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d"
+  integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==
 
 redent@^3.0.0:
   version "3.0.0"
@@ -3866,10 +4320,19 @@
     indent-string "^4.0.0"
     strip-indent "^3.0.0"
 
-regenerator-runtime@^0.14.0:
-  version "0.14.1"
-  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
-  integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
+reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9"
+  integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==
+  dependencies:
+    call-bind "^1.0.8"
+    define-properties "^1.2.1"
+    es-abstract "^1.23.9"
+    es-errors "^1.3.0"
+    es-object-atoms "^1.0.0"
+    get-intrinsic "^1.2.7"
+    get-proto "^1.0.1"
+    which-builtin-type "^1.2.1"
 
 regex-not@^1.0.0, regex-not@^1.0.2:
   version "1.0.2"
@@ -3879,14 +4342,16 @@
     extend-shallow "^3.0.2"
     safe-regex "^1.1.0"
 
-regexp.prototype.flags@^1.5.2:
-  version "1.5.3"
-  resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42"
-  integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==
+regexp.prototype.flags@^1.5.3:
+  version "1.5.4"
+  resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19"
+  integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==
   dependencies:
-    call-bind "^1.0.7"
+    call-bind "^1.0.8"
     define-properties "^1.2.1"
     es-errors "^1.3.0"
+    get-proto "^1.0.1"
+    gopd "^1.2.0"
     set-function-name "^2.0.2"
 
 regexpp@^3.0.0:
@@ -3932,17 +4397,22 @@
     http-errors "~1.6.2"
     path-is-absolute "1.0.1"
 
+resolve-pkg-maps@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f"
+  integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==
+
 resolve-url@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
   integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==
 
-resolve@^1.10.0, resolve@^1.10.1, resolve@^1.19.0, resolve@^1.22.4:
-  version "1.22.8"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
-  integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
+resolve@^1.10.0, resolve@^1.22.1, resolve@^1.22.4:
+  version "1.22.10"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39"
+  integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==
   dependencies:
-    is-core-module "^2.13.0"
+    is-core-module "^2.16.0"
     path-parse "^1.0.7"
     supports-preserve-symlinks-flag "^1.0.0"
 
@@ -3964,49 +4434,53 @@
   resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
   integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
 
-rimraf@^3.0.2:
+rimraf@3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
   integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
   dependencies:
     glob "^7.1.3"
 
-rollup@^2.67.0:
-  version "2.79.1"
-  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
-  integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
-  optionalDependencies:
-    fsevents "~2.3.2"
-
-rollup@^4.40.0:
-  version "4.40.0"
-  resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.40.0.tgz#13742a615f423ccba457554f006873d5a4de1920"
-  integrity sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==
+rollup@^4.4.0, rollup@^4.40.0:
+  version "4.41.0"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.41.0.tgz#17476835d2967759e3ffebe5823ed15fc4b7d13e"
+  integrity sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==
   dependencies:
     "@types/estree" "1.0.7"
   optionalDependencies:
-    "@rollup/rollup-android-arm-eabi" "4.40.0"
-    "@rollup/rollup-android-arm64" "4.40.0"
-    "@rollup/rollup-darwin-arm64" "4.40.0"
-    "@rollup/rollup-darwin-x64" "4.40.0"
-    "@rollup/rollup-freebsd-arm64" "4.40.0"
-    "@rollup/rollup-freebsd-x64" "4.40.0"
-    "@rollup/rollup-linux-arm-gnueabihf" "4.40.0"
-    "@rollup/rollup-linux-arm-musleabihf" "4.40.0"
-    "@rollup/rollup-linux-arm64-gnu" "4.40.0"
-    "@rollup/rollup-linux-arm64-musl" "4.40.0"
-    "@rollup/rollup-linux-loongarch64-gnu" "4.40.0"
-    "@rollup/rollup-linux-powerpc64le-gnu" "4.40.0"
-    "@rollup/rollup-linux-riscv64-gnu" "4.40.0"
-    "@rollup/rollup-linux-riscv64-musl" "4.40.0"
-    "@rollup/rollup-linux-s390x-gnu" "4.40.0"
-    "@rollup/rollup-linux-x64-gnu" "4.40.0"
-    "@rollup/rollup-linux-x64-musl" "4.40.0"
-    "@rollup/rollup-win32-arm64-msvc" "4.40.0"
-    "@rollup/rollup-win32-ia32-msvc" "4.40.0"
-    "@rollup/rollup-win32-x64-msvc" "4.40.0"
+    "@rollup/rollup-android-arm-eabi" "4.41.0"
+    "@rollup/rollup-android-arm64" "4.41.0"
+    "@rollup/rollup-darwin-arm64" "4.41.0"
+    "@rollup/rollup-darwin-x64" "4.41.0"
+    "@rollup/rollup-freebsd-arm64" "4.41.0"
+    "@rollup/rollup-freebsd-x64" "4.41.0"
+    "@rollup/rollup-linux-arm-gnueabihf" "4.41.0"
+    "@rollup/rollup-linux-arm-musleabihf" "4.41.0"
+    "@rollup/rollup-linux-arm64-gnu" "4.41.0"
+    "@rollup/rollup-linux-arm64-musl" "4.41.0"
+    "@rollup/rollup-linux-loongarch64-gnu" "4.41.0"
+    "@rollup/rollup-linux-powerpc64le-gnu" "4.41.0"
+    "@rollup/rollup-linux-riscv64-gnu" "4.41.0"
+    "@rollup/rollup-linux-riscv64-musl" "4.41.0"
+    "@rollup/rollup-linux-s390x-gnu" "4.41.0"
+    "@rollup/rollup-linux-x64-gnu" "4.41.0"
+    "@rollup/rollup-linux-x64-musl" "4.41.0"
+    "@rollup/rollup-win32-arm64-msvc" "4.41.0"
+    "@rollup/rollup-win32-ia32-msvc" "4.41.0"
+    "@rollup/rollup-win32-x64-msvc" "4.41.0"
     fsevents "~2.3.2"
 
+router@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef"
+  integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==
+  dependencies:
+    debug "^4.4.0"
+    depd "^2.0.0"
+    is-promise "^4.0.0"
+    parseurl "^1.3.3"
+    path-to-regexp "^8.0.0"
+
 run-async@^2.4.0:
   version "2.4.1"
   resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
@@ -4026,14 +4500,15 @@
   dependencies:
     tslib "^1.9.0"
 
-safe-array-concat@^1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb"
-  integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==
+safe-array-concat@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3"
+  integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==
   dependencies:
-    call-bind "^1.0.7"
-    get-intrinsic "^1.2.4"
-    has-symbols "^1.0.3"
+    call-bind "^1.0.8"
+    call-bound "^1.0.2"
+    get-intrinsic "^1.2.6"
+    has-symbols "^1.1.0"
     isarray "^2.0.5"
 
 safe-buffer@5.2.1:
@@ -4041,14 +4516,22 @@
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
   integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
 
-safe-regex-test@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377"
-  integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==
+safe-push-apply@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5"
+  integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==
   dependencies:
-    call-bind "^1.0.6"
     es-errors "^1.3.0"
-    is-regex "^1.1.4"
+    isarray "^2.0.5"
+
+safe-regex-test@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1"
+  integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==
+  dependencies:
+    call-bound "^1.0.2"
+    es-errors "^1.3.0"
+    is-regex "^1.2.1"
 
 safe-regex@^1.1.0:
   version "1.1.0"
@@ -4057,7 +4540,7 @@
   dependencies:
     ret "~0.1.10"
 
-"safer-buffer@>= 2.1.2 < 3":
+"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
   integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@@ -4072,24 +4555,54 @@
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
   integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
 
-semver@^6.1.0, semver@^6.3.1:
+semver@^6.3.1:
   version "6.3.1"
   resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
   integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
 
-semver@^7.3.4, semver@^7.3.7, semver@^7.5.1:
-  version "7.5.4"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
-  integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+semver@^7.0.0, semver@^7.3.4, semver@^7.3.8, semver@^7.5.4, semver@^7.6.3:
+  version "7.7.2"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58"
+  integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==
+
+semver@^7.6.0:
+  version "7.7.1"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f"
+  integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
+
+send@^1.1.0, send@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/send/-/send-1.2.0.tgz#32a7554fb777b831dfa828370f773a3808d37212"
+  integrity sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==
   dependencies:
-    lru-cache "^6.0.0"
+    debug "^4.3.5"
+    encodeurl "^2.0.0"
+    escape-html "^1.0.3"
+    etag "^1.8.1"
+    fresh "^2.0.0"
+    http-errors "^2.0.0"
+    mime-types "^3.0.1"
+    ms "^2.1.3"
+    on-finished "^2.4.1"
+    range-parser "^1.2.1"
+    statuses "^2.0.1"
+
+serve-static@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-2.2.0.tgz#9c02564ee259bdd2251b82d659a2e7e1938d66f9"
+  integrity sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==
+  dependencies:
+    encodeurl "^2.0.0"
+    escape-html "^1.0.3"
+    parseurl "^1.3.3"
+    send "^1.2.0"
 
 set-blocking@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
   integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
 
-set-function-length@^1.2.1:
+set-function-length@^1.2.2:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
   integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
@@ -4111,6 +4624,15 @@
     functions-have-names "^1.2.3"
     has-property-descriptors "^1.0.2"
 
+set-proto@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/set-proto/-/set-proto-1.0.0.tgz#0760dbcff30b2d7e801fd6e19983e56da337565e"
+  integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==
+  dependencies:
+    dunder-proto "^1.0.1"
+    es-errors "^1.3.0"
+    es-object-atoms "^1.0.0"
+
 set-value@^2.0.0, set-value@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
@@ -4156,30 +4678,55 @@
   integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
 
 shell-quote@^1.6.1:
-  version "1.8.1"
-  resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
-  integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.2.tgz#d2d83e057959d53ec261311e9e9b8f51dcb2934a"
+  integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==
 
-side-channel@^1.0.4:
-  version "1.0.6"
-  resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
-  integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
+side-channel-list@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad"
+  integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==
   dependencies:
-    call-bind "^1.0.7"
     es-errors "^1.3.0"
-    get-intrinsic "^1.2.4"
-    object-inspect "^1.13.1"
+    object-inspect "^1.13.3"
 
-signal-exit@^3.0.2, signal-exit@^3.0.3:
+side-channel-map@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42"
+  integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==
+  dependencies:
+    call-bound "^1.0.2"
+    es-errors "^1.3.0"
+    get-intrinsic "^1.2.5"
+    object-inspect "^1.13.3"
+
+side-channel-weakmap@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea"
+  integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==
+  dependencies:
+    call-bound "^1.0.2"
+    es-errors "^1.3.0"
+    get-intrinsic "^1.2.5"
+    object-inspect "^1.13.3"
+    side-channel-map "^1.0.1"
+
+side-channel@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9"
+  integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==
+  dependencies:
+    es-errors "^1.3.0"
+    object-inspect "^1.13.3"
+    side-channel-list "^1.0.0"
+    side-channel-map "^1.0.1"
+    side-channel-weakmap "^1.0.2"
+
+signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
   version "3.0.7"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
   integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
 
-slash@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
-  integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
-
 snapdragon-node@^2.0.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@@ -4261,11 +4808,11 @@
     spdx-license-ids "^3.0.0"
 
 spdx-exceptions@^2.1.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
-  integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66"
+  integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==
 
-spdx-expression-parse@^3.0.0, spdx-expression-parse@^3.0.1:
+spdx-expression-parse@^3.0.0:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
   integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
@@ -4273,10 +4820,18 @@
     spdx-exceptions "^2.1.0"
     spdx-license-ids "^3.0.0"
 
+spdx-expression-parse@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz#a23af9f3132115465dac215c099303e4ceac5794"
+  integrity sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==
+  dependencies:
+    spdx-exceptions "^2.1.0"
+    spdx-license-ids "^3.0.0"
+
 spdx-license-ids@^3.0.0:
-  version "3.0.16"
-  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz#a14f64e0954f6e25cc6587bd4f392522db0d998f"
-  integrity sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==
+  version "3.0.21"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz#6d6e980c9df2b6fc905343a3b2d702a6239536c3"
+  integrity sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==
 
 split-string@^3.0.1, split-string@^3.0.2:
   version "3.1.0"
@@ -4293,16 +4848,16 @@
     define-property "^0.2.5"
     object-copy "^0.1.0"
 
+statuses@2.0.1, statuses@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+  integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
 "statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@^1.5.0:
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
   integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
 
-stream-read-all@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/stream-read-all/-/stream-read-all-3.0.1.tgz#60762ae45e61d93ba0978cda7f3913790052ad96"
-  integrity sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A==
-
 string-width@^4.1.0, string-width@^4.2.0:
   version "4.2.3"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
@@ -4313,30 +4868,35 @@
     strip-ansi "^6.0.1"
 
 string.prototype.padend@^3.0.0:
-  version "3.1.5"
-  resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.5.tgz#311ef3a4e3c557dd999cdf88fbdde223f2ac0f95"
-  integrity sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==
-  dependencies:
-    call-bind "^1.0.2"
-    define-properties "^1.2.0"
-    es-abstract "^1.22.1"
-
-string.prototype.trim@^1.2.9:
-  version "1.2.9"
-  resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4"
-  integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==
+  version "3.1.6"
+  resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz#ba79cf8992609a91c872daa47c6bb144ee7f62a5"
+  integrity sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==
   dependencies:
     call-bind "^1.0.7"
     define-properties "^1.2.1"
-    es-abstract "^1.23.0"
+    es-abstract "^1.23.2"
     es-object-atoms "^1.0.0"
 
-string.prototype.trimend@^1.0.8:
-  version "1.0.8"
-  resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229"
-  integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==
+string.prototype.trim@^1.2.10:
+  version "1.2.10"
+  resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81"
+  integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==
   dependencies:
-    call-bind "^1.0.7"
+    call-bind "^1.0.8"
+    call-bound "^1.0.2"
+    define-data-property "^1.1.4"
+    define-properties "^1.2.1"
+    es-abstract "^1.23.5"
+    es-object-atoms "^1.0.0"
+    has-property-descriptors "^1.0.2"
+
+string.prototype.trimend@^1.0.8, string.prototype.trimend@^1.0.9:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942"
+  integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==
+  dependencies:
+    call-bind "^1.0.8"
+    call-bound "^1.0.2"
     define-properties "^1.2.1"
     es-object-atoms "^1.0.0"
 
@@ -4397,34 +4957,44 @@
   resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
   integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
 
-table-layout@^3.0.0:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-3.0.2.tgz#69c2be44388a5139b48c59cf21e73b488021769a"
-  integrity sha512-rpyNZYRw+/C+dYkcQ3Pr+rLxW4CfHpXjPDnG7lYhdRoUcZTUt+KEsX+94RGp/aVp/MQU35JCITv2T/beY4m+hw==
+synckit@^0.11.0:
+  version "0.11.6"
+  resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.6.tgz#e742a0c27bbc1fbc96f2010770521015cca7ed5c"
+  integrity sha512-2pR2ubZSV64f/vqm9eLPz/KOvR9Dm+Co/5ChLgeHl0yEDRc6h5hXHoxEQH8Y5Ljycozd3p1k5TTSVdzYGkPvLw==
   dependencies:
-    "@75lb/deep-merge" "^1.1.1"
+    "@pkgr/core" "^0.2.4"
+
+synckit@^0.9.1:
+  version "0.9.2"
+  resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62"
+  integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==
+  dependencies:
+    "@pkgr/core" "^0.1.0"
+    tslib "^2.6.2"
+
+table-layout@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-4.1.1.tgz#0f72965de1a5c0c1419c9ba21cae4e73a2f73a42"
+  integrity sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==
+  dependencies:
     array-back "^6.2.2"
-    command-line-args "^5.2.1"
-    command-line-usage "^7.0.0"
-    stream-read-all "^3.0.1"
-    typical "^7.1.1"
     wordwrapjs "^5.1.0"
 
+tapable@^2.2.0:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
+  integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+
 terser@~5.39.0:
-  version "5.39.0"
-  resolved "https://registry.yarnpkg.com/terser/-/terser-5.39.0.tgz#0e82033ed57b3ddf1f96708d123cca717d86ca3a"
-  integrity sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==
+  version "5.39.2"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-5.39.2.tgz#5a1626030724a672e2e5b5c9cd9070308c20e8f9"
+  integrity sha512-yEPUmWve+VA78bI71BW70Dh0TuV4HHd+I5SHOAfS1+QBOmvmCiiffgjR8ryyEd3KIfvPGFqoADt8LdQ6XpXIvg==
   dependencies:
     "@jridgewell/source-map" "^0.3.3"
-    acorn "^8.8.2"
+    acorn "^8.14.0"
     commander "^2.20.0"
     source-map-support "~0.5.20"
 
-text-table@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
-  integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
-
 through@^2.3.6:
   version "2.3.8"
   resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@@ -4474,18 +5044,23 @@
   resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
   integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
 
-tr46@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9"
-  integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==
+tr46@^5.1.0:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.1.1.tgz#96ae867cddb8fdb64a49cc3059a8d428bcf238ca"
+  integrity sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==
   dependencies:
-    punycode "^2.1.1"
+    punycode "^2.3.1"
 
 trim-newlines@^3.0.0:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
   integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
 
+ts-api-utils@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91"
+  integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==
+
 ts-lit-plugin@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/ts-lit-plugin/-/ts-lit-plugin-1.2.1.tgz#7fca17a454645c14911917fa7f17ade582fa3056"
@@ -4513,12 +5088,17 @@
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
 
+tslib@^2.6.2:
+  version "2.8.1"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
+  integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
+
 tsscmp@1.0.6:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"
   integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==
 
-tsutils@3.21.0, tsutils@^3.21.0:
+tsutils@3.21.0:
   version "3.21.0"
   resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
   integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
@@ -4537,11 +5117,6 @@
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
   integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
 
-type-fest@^0.20.2:
-  version "0.20.2"
-  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
-  integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
-
 type-fest@^0.21.3:
   version "0.21.3"
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
@@ -4565,56 +5140,59 @@
     media-typer "0.3.0"
     mime-types "~2.1.24"
 
-typed-array-buffer@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3"
-  integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==
+type-is@^2.0.0, type-is@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97"
+  integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==
   dependencies:
-    call-bind "^1.0.7"
+    content-type "^1.0.5"
+    media-typer "^1.1.0"
+    mime-types "^3.0.0"
+
+typed-array-buffer@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536"
+  integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==
+  dependencies:
+    call-bound "^1.0.3"
     es-errors "^1.3.0"
-    is-typed-array "^1.1.13"
+    is-typed-array "^1.1.14"
 
-typed-array-byte-length@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67"
-  integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==
+typed-array-byte-length@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce"
+  integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==
   dependencies:
-    call-bind "^1.0.7"
+    call-bind "^1.0.8"
     for-each "^0.3.3"
-    gopd "^1.0.1"
-    has-proto "^1.0.3"
-    is-typed-array "^1.1.13"
+    gopd "^1.2.0"
+    has-proto "^1.2.0"
+    is-typed-array "^1.1.14"
 
-typed-array-byte-offset@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063"
-  integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==
+typed-array-byte-offset@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355"
+  integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==
   dependencies:
     available-typed-arrays "^1.0.7"
-    call-bind "^1.0.7"
+    call-bind "^1.0.8"
     for-each "^0.3.3"
-    gopd "^1.0.1"
-    has-proto "^1.0.3"
-    is-typed-array "^1.1.13"
+    gopd "^1.2.0"
+    has-proto "^1.2.0"
+    is-typed-array "^1.1.15"
+    reflect.getprototypeof "^1.0.9"
 
-typed-array-length@^1.0.6:
-  version "1.0.6"
-  resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3"
-  integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==
+typed-array-length@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d"
+  integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==
   dependencies:
     call-bind "^1.0.7"
     for-each "^0.3.3"
     gopd "^1.0.1"
-    has-proto "^1.0.3"
     is-typed-array "^1.1.13"
     possible-typed-array-names "^1.0.0"
-
-typedarray-to-buffer@^3.1.5:
-  version "3.1.5"
-  resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
-  integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
-  dependencies:
-    is-typedarray "^1.0.0"
+    reflect.getprototypeof "^1.0.6"
 
 typescript@^3.8.3:
   version "3.9.10"
@@ -4632,29 +5210,29 @@
   integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
 
 typical@^7.1.1:
-  version "7.1.1"
-  resolved "https://registry.yarnpkg.com/typical/-/typical-7.1.1.tgz#ba177ab7ab103b78534463ffa4c0c9754523ac1f"
-  integrity sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==
+  version "7.3.0"
+  resolved "https://registry.yarnpkg.com/typical/-/typical-7.3.0.tgz#930376be344228709f134613911fa22aa09617a4"
+  integrity sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==
 
 ua-parser-js@^1.0.33:
-  version "1.0.37"
-  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.37.tgz#b5dc7b163a5c1f0c510b08446aed4da92c46373f"
-  integrity sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==
+  version "1.0.40"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.40.tgz#ac6aff4fd8ea3e794a6aa743ec9c2fc29e75b675"
+  integrity sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==
 
-unbox-primitive@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
-  integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
+unbox-primitive@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2"
+  integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==
   dependencies:
-    call-bind "^1.0.2"
+    call-bound "^1.0.3"
     has-bigints "^1.0.2"
-    has-symbols "^1.0.3"
-    which-boxed-primitive "^1.0.2"
+    has-symbols "^1.1.0"
+    which-boxed-primitive "^1.1.1"
 
-undici-types@~5.26.4:
-  version "5.26.5"
-  resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
-  integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+undici-types@~6.21.0:
+  version "6.21.0"
+  resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb"
+  integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
 
 union-value@^1.0.0:
   version "1.0.1"
@@ -4666,6 +5244,11 @@
     is-extendable "^0.1.1"
     set-value "^2.0.1"
 
+unpipe@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+  integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
 unset-value@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
@@ -4699,7 +5282,7 @@
     spdx-correct "^3.0.0"
     spdx-expression-parse "^3.0.0"
 
-vary@^1.1.2:
+vary@^1, vary@^1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
   integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
@@ -4725,9 +5308,9 @@
     vscode-uri "^2.1.2"
 
 vscode-languageserver-textdocument@^1.0.1:
-  version "1.0.11"
-  resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz#0822a000e7d4dc083312580d7575fe9e3ba2e2bf"
-  integrity sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==
+  version "1.0.12"
+  resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz#457ee04271ab38998a093c68c2342f53f6e4a631"
+  integrity sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==
 
 vscode-languageserver-types@3.16.0-next.2:
   version "3.16.0-next.2"
@@ -4759,39 +5342,70 @@
   resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a"
   integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==
 
-whatwg-url@^11.0.0:
-  version "11.0.0"
-  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018"
-  integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==
+whatwg-url@^14.0.0:
+  version "14.2.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.2.0.tgz#4ee02d5d725155dae004f6ae95c73e7ef5d95663"
+  integrity sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==
   dependencies:
-    tr46 "^3.0.0"
+    tr46 "^5.1.0"
     webidl-conversions "^7.0.0"
 
-which-boxed-primitive@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
-  integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
+which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e"
+  integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==
   dependencies:
-    is-bigint "^1.0.1"
-    is-boolean-object "^1.1.0"
-    is-number-object "^1.0.4"
-    is-string "^1.0.5"
-    is-symbol "^1.0.3"
+    is-bigint "^1.1.0"
+    is-boolean-object "^1.2.1"
+    is-number-object "^1.1.1"
+    is-string "^1.1.1"
+    is-symbol "^1.1.1"
+
+which-builtin-type@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e"
+  integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==
+  dependencies:
+    call-bound "^1.0.2"
+    function.prototype.name "^1.1.6"
+    has-tostringtag "^1.0.2"
+    is-async-function "^2.0.0"
+    is-date-object "^1.1.0"
+    is-finalizationregistry "^1.1.0"
+    is-generator-function "^1.0.10"
+    is-regex "^1.2.1"
+    is-weakref "^1.0.2"
+    isarray "^2.0.5"
+    which-boxed-primitive "^1.1.0"
+    which-collection "^1.0.2"
+    which-typed-array "^1.1.16"
+
+which-collection@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0"
+  integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==
+  dependencies:
+    is-map "^2.0.3"
+    is-set "^2.0.3"
+    is-weakmap "^2.0.2"
+    is-weakset "^2.0.3"
 
 which-module@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409"
   integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==
 
-which-typed-array@^1.1.14, which-typed-array@^1.1.15:
-  version "1.1.15"
-  resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d"
-  integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==
+which-typed-array@^1.1.16, which-typed-array@^1.1.18:
+  version "1.1.19"
+  resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956"
+  integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==
   dependencies:
     available-typed-arrays "^1.0.7"
-    call-bind "^1.0.7"
-    for-each "^0.3.3"
-    gopd "^1.0.1"
+    call-bind "^1.0.8"
+    call-bound "^1.0.4"
+    for-each "^0.3.5"
+    get-proto "^1.0.1"
+    gopd "^1.2.0"
     has-tostringtag "^1.0.2"
 
 which@^1.2.9:
@@ -4832,20 +5446,18 @@
   resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
   integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
 
-write-file-atomic@^3.0.3:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
-  integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
+write-file-atomic@^4.0.0:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd"
+  integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==
   dependencies:
     imurmurhash "^0.1.4"
-    is-typedarray "^1.0.0"
-    signal-exit "^3.0.2"
-    typedarray-to-buffer "^3.1.5"
+    signal-exit "^3.0.7"
 
-ws@^7.4.2:
-  version "7.5.9"
-  resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
-  integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
+ws@^7.5.10:
+  version "7.5.10"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9"
+  integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==
 
 y18n@^4.0.0:
   version "4.0.3"
@@ -4888,11 +5500,21 @@
     yargs-parser "^18.1.2"
 
 ylru@^1.2.0:
-  version "1.3.2"
-  resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.3.2.tgz#0de48017473275a4cbdfc83a1eaf67c01af8a785"
-  integrity sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.4.0.tgz#0cf0aa57e9c24f8a2cbde0cc1ca2c9592ac4e0f6"
+  integrity sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA==
 
 yocto-queue@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
   integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+
+zod-to-json-schema@^3.24.1:
+  version "3.24.5"
+  resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz#d1095440b147fb7c2093812a53c54df8d5df50a3"
+  integrity sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==
+
+zod@^3.23.8, zod@^3.24.2:
+  version "3.24.4"
+  resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.4.tgz#e2e2cca5faaa012d76e527d0d36622e0a90c315f"
+  integrity sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==