Repository: hello-robot/stretch_web_teleop
Pull request #45: Add JS(X)/TS(X) linting
Author: login: hello-amal
Created: 2024-05-21T22:07:52Z | Merged: 2025-05-09T21:38:14Z

# Description

This PR, in partial service of #43 , builds off of #44 to add JS(X)/TS(X) linting.

This PR is a work-in-progress; although the pre-commit hooks are properly configured to lint the repository (and that has been tested), they generate hundreds of warnings/errors. Most are straightforward to fix, but some fixes require legacy knowledge of the codebase (e.g., [the fact that `relativePose` no longer exists as a type](https://github.com/hello-robot/stretch_web_teleop/blob/34ff6810f768c120f7b0b17105df699f07ab15af/src/pages/operator/tsx/index.tsx#L157)). Those lint errors are better suited for @hello-vinitha to address.

# Testing procedure

TODO

# Before opening a pull request

From the top-level of this repository, run:

- \[ \] `pre-commit run --all-files`

# To merge

- \[ \] `Squash & Merge`


Diff:
diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml
index b1812740..2628df53 100644
--- a/.github/workflows/pre-commit.yaml
+++ b/.github/workflows/pre-commit.yaml
@@ -1,34 +1,71 @@
 name: pre-commit
 
 on:
+  # Run on push to master
   push:
     branches:
-      - main
       - master
+  # Run on pull request actions
   pull_request:
-    types: [opened, reopened, synchronize, review_requested, ready_for_review]
+    types: [opened, reopened, synchronize]
+  # Manual trigger
   workflow_dispatch:
 
+# Prevent parallel runs
 concurrency:
   group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
   cancel-in-progress: true
 
+# Global env vars
 env:
   PYTHON_VERSION: "3.10"
 
 jobs:
   pre-commit:
     runs-on: ubuntu-latest
-    if: ${{ !github.event.pull_request.draft }}
     steps:
-      - uses: actions/checkout@v4
-      - uses: actions/setup-python@v5
+      # Checkout code and keep creds for push
+      - name: Checkout repo
+        uses: actions/checkout@v4
+        with:
+          persist-credentials: true
+
+      # Setup Python
+      - name: Setup Python
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ env.PYTHON_VERSION }}
 
-      ## Run pre-commit and try to apply fixes
-      - name: Run pre-commit
+      # Setup Node.js for JS hooks
+      - name: Use Node.js 21.x
+        uses: actions/setup-node@v3
+        with:
+          node-version: "21.x"
+
+      # Cache NPM deps
+      - name: Cache NPM
+        uses: actions/cache@v3
+        with:
+          path: ~/.npm
+          key: ${{ runner.os }}-npm-
+          restore-keys: |
+            ${{ runner.os }}-npm-
+
+      # Cache pip for Python hook installs
+      - name: Cache pip
+        uses: actions/cache@v3
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+          restore-keys: |
+            ${{ runner.os }}-pip-
+
+      # Install JS devDependencies
+      - name: Install devDependencies
+        run: npm install --legacy-peer-deps
+
+      # Run pre-commit in check-only mode (fail on any diffs)
+      - name: Run pre-commit (check-only)
         uses: pre-commit/action@v3.0.1
-      - name: Apply fixes from pre-commit
-        uses: pre-commit-ci/lite-action@v1.0.2
-        if: always()
+        with:
+          args: run --all-files --show-diff-on-failure
diff --git a/.gitignore b/.gitignore
index 634a2bc7..ad432f3e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,7 +18,6 @@
 .env.development.local
 .env.test.local
 .env.production.local
-.vscode
 
 npm-debug.log*
 yarn-debug.log*
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 544cbb4e..a97da379 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -22,47 +22,48 @@ repos:
       - id: trailing-whitespace
         exclude: config/text_to_speech_ui_history.txt
 
-  # isort auto-sorts Python imports
   - repo: https://github.com/pycqa/isort
     rev: 5.12.0
     hooks:
       - id: isort
-        args: ["--profile", "black"]
+        args: ["--profile", "black", "--check"]
 
-  # Black formats Python code
   - repo: https://github.com/psf/black
     rev: 23.1.0
     hooks:
       - id: black
+        args: ["--check"]
 
-  # Flake8 lints Python code
   - repo: https://github.com/pycqa/flake8
     rev: 5.0.4
     hooks:
       - id: flake8
 
-  # MyPy does static type-checking in Python
-  # Note: In practice this doesn't currently do much, since we don't have type hints in our Python scripts.
   - repo: https://github.com/pre-commit/mirrors-mypy
     rev: v0.981
     hooks:
       - id: mypy
-        args: [--install-types, --non-interactive, --no-strict-optional, --ignore-missing-imports]
+        args:
+          [
+            --install-types,
+            --non-interactive,
+            --no-strict-optional,
+            --ignore-missing-imports,
+          ]
 
-  # Beautysh formats Bash scripts
   - repo: https://github.com/lovesegfault/beautysh
     rev: v6.2.1
     hooks:
       - id: beautysh
+        args: ["--check"]
 
-  # Mdformat formats Markdown files
   - repo: https://github.com/executablebooks/mdformat
     rev: 0.7.16
     hooks:
       - id: mdformat
-        exclude: \.github/.*  # Exclude files in the .github directory
+        args: ["--check"]
+        exclude: \.github/.*
 
-  # Codespell checks the code for common misspellings
   - repo: https://github.com/codespell-project/codespell
     rev: v2.2.4
     hooks:
@@ -72,17 +73,9 @@ repos:
               .*\.svg
           )$
 
-  # Prettier formats JS(X), TS(X), HTML, CSS, etc. files
-  - repo: https://github.com/pre-commit/mirrors-prettier
-    rev: v4.0.0-alpha.8
+  - repo: https://github.com/pre-commit/mirrors-eslint
+    rev: "v8.56.0"
     hooks:
-      - id: prettier
-        types_or: [css, html, javascript, json, jsx, ts, tsx]
-
-  # # ESLint lints Javascript/Typescript files
-  # - repo: https://github.com/pre-commit/mirrors-eslint
-  #   rev: 'v8.56.0'  # Use the sha / tag you want to point at
-  #   hooks:
-  #   -   id: eslint
-  #       files: \.[jt]sx?$  # *.js, *.jsx, *.ts and *.tsx
-  #       types: [file]
+      - id: eslint
+        files: \.[jt]sx?$
+        types: [file]
diff --git a/.prettierrc b/.prettierrc
index 0a02bcef..f3d63e58 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,3 +1,9 @@
 {
-    "tabWidth": 4
+    "tabWidth": 4,
+    "useTabs": false,
+    "singleQuote": false,
+    "printWidth": 80,
+    "trailingComma": "es5",
+    "semi": true,
+    "endOfLine": "lf"
 }
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 00000000..974188b8
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,3 @@
+{
+    "recommendations": ["esbenp.prettier-vscode"]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..02b880e8
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+    "editor.formatOnSave": true,
+    "editor.defaultFormatter": "esbenp.prettier-vscode",
+    "prettier.requireConfig": true
+}
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 00000000..2dfa5edc
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,73 @@
+import { defineConfig } from "eslint/config";
+import { fixupConfigRules } from "@eslint/compat";
+import globals from "globals";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import js from "@eslint/js";
+import { FlatCompat } from "@eslint/eslintrc";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const compat = new FlatCompat({
+    baseDirectory: __dirname,
+    recommendedConfig: js.configs.recommended,
+    allConfig: js.configs.all,
+});
+
+export default defineConfig([
+    {
+        extends: fixupConfigRules(
+            compat.extends(
+                "eslint:recommended",
+                "react-app",
+                "plugin:react/recommended",
+                "plugin:react-hooks/recommended",
+                "plugin:prettier/recommended"
+            )
+        ),
+
+        languageOptions: {
+            globals: {
+                ...globals.jest,
+                ...globals.browser,
+                ...globals.amd,
+                ...globals.node,
+            },
+
+            ecmaVersion: 2020,
+            sourceType: "module",
+
+            parserOptions: {
+                ecmaFeatures: {
+                    jsx: true,
+                },
+            },
+        },
+
+        settings: {
+            react: {
+                version: "detect",
+            },
+        },
+
+        rules: {
+            "prettier/prettier": [
+                "error",
+                {},
+                {
+                    usePrettierrc: true,
+                },
+            ],
+            eqeqeq: "off",
+            // allow double-quotes (and auto-fix to double)
+            quotes: [
+                "error",
+                "double",
+                {
+                    avoidEscape: true, // still let ya use single if you gotta avoid escape
+                    allowTemplateLiterals: true, // keep backticks workin’ for templates
+                },
+            ],
+        },
+    },
+]);
diff --git a/package.json b/package.json
index 591a674c..712f2970 100644
--- a/package.json
+++ b/package.json
@@ -69,10 +69,20 @@
         "@babel/preset-env": "^7.22.6",
         "@babel/preset-react": "^7.18.6",
         "@babel/preset-typescript": "^7.21.4",
+        "@eslint/compat": "^1.2.8",
+        "@eslint/eslintrc": "^3.3.1",
+        "@eslint/js": "^9.25.1",
         "@types/node": "^20.6.0",
         "@types/three": "^0.157.0",
         "babel-loader": "^9.1.2",
         "babel-polyfill": "^6.26.0",
+        "eslint": "^9.25.1",
+        "eslint-config-prettier": "^9.1.0",
+        "eslint-plugin-prettier": "^5.1.3",
+        "eslint-plugin-react": "^7.34.1",
+        "eslint-plugin-react-hooks": "^4.6.2",
+        "globals": "^16.0.0",
+        "prettier": "3.2.5",
         "react-docgen-typescript": "^2.2.2",
         "react-styleguidist": "^13.1.1",
         "typescript": "^5.2.2",
diff --git a/server.js b/server.js
index b57b68ff..ed6790b5 100644
--- a/server.js
+++ b/server.js
@@ -1,53 +1,53 @@
-var fs = require("fs");
-require("dotenv").config();
+var fs = require('fs');
+require('dotenv').config();
 
 var options = {
     key: fs.readFileSync(`certificates/${process.env.keyfile}`),
     cert: fs.readFileSync(`certificates/${process.env.certfile}`),
 };
 
-const socket = require("socket.io");
-var express = require("express");
+const socket = require('socket.io');
+var express = require('express');
 var app = express();
-app.all("*", ensureSecure); // at top of routing calls
+app.all('*', ensureSecure); // at top of routing calls
 
 function ensureSecure(req, res, next) {
     if (!req.secure) {
         // handle port numbers if you need non defaults
-        console.log("redirecting insecure request");
-        return res.redirect("https://" + req.hostname + req.url);
+        console.log('redirecting insecure request');
+        return res.redirect('https://' + req.hostname + req.url);
         // res.redirect(`https://${req.hostname}${process.env.NGROK_URL}`);
     }
 
     return next();
 }
 
-var server = require("http").Server(app);
-var secure_server = require("https").Server(options, app);
+var server = require('http').Server(app);
+var secure_server = require('https').Server(options, app);
 const io = socket(secure_server, {
     allowEIO3: true,
 });
-app.enable("trust proxy");
-app.set("port", 443);
+app.enable('trust proxy');
+app.set('port', 443);
 server.listen(80);
 secure_server.listen(443);
 
-var path = require("path");
-app.use("/", express.static(path.join(__dirname, "dist")));
+var path = require('path');
+app.use('/', express.static(path.join(__dirname, 'dist')));
 
 app.listen(process.env.port);
 
-io.on("connect_error", (err) => {
+io.on('connect_error', (err) => {
     console.log(`connect_error due to ${err.message}`);
 });
 
-ROOM = "default";
+const ROOM = 'default';
 let robo_sock = undefined;
 let oper_sock = undefined;
 let protocol = undefined; // TODO(binit): ensure robot/operator protocol match
-let status = "offline"; // ["online", "offline", "occupied"]
+let status = 'offline'; // ["online", "offline", "occupied"]
 function updateRooms() {
-    io.emit("update_rooms", {
+    io.emit('update_rooms', {
         robot_id: {
             name: process.env.HELLO_FLEET_ID,
             protocol: protocol,
@@ -56,94 +56,94 @@ function updateRooms() {
     });
 }
 
-io.on("connection", function (socket) {
-    console.log("new socket.io connection");
+io.on('connection', function (socket) {
+    console.log('new socket.io connection');
     // console.log('socket.handshake = ');
     // console.log(socket.handshake);
 
-    socket.on("join_as_robot", (callback) => {
-        console.log("Received join_as_robot request");
+    socket.on('join_as_robot', (callback) => {
+        console.log('Received join_as_robot request');
         if (!robo_sock) {
             socket.join(ROOM);
             robo_sock = socket.id;
-            status = "online";
-            console.log("join_as_robot SUCCESS");
+            status = 'online';
+            console.log('join_as_robot SUCCESS');
             callback({ success: true });
         } else {
-            status = "occupied";
-            console.log("join_as_robot FAILURE");
+            status = 'occupied';
+            console.log('join_as_robot FAILURE');
             callback({ success: false });
         }
         updateRooms();
     });
 
-    socket.on("list_rooms", () => {
+    socket.on('list_rooms', () => {
         updateRooms();
     });
 
-    socket.on("join_as_operator", (callback) => {
-        console.log("Received join_as_operator request");
+    socket.on('join_as_operator', (callback) => {
+        console.log('Received join_as_operator request');
         if (robo_sock) {
-            status = "occupied";
+            status = 'occupied';
             if (!oper_sock) {
                 socket.join(ROOM);
-                socket.in(ROOM).emit("joined");
+                socket.in(ROOM).emit('joined');
                 oper_sock = socket.id;
-                console.log("join_as_operator SUCCESS");
+                console.log('join_as_operator SUCCESS');
                 callback({ success: true });
             } else {
                 console.log(
-                    "join_as_operator FAILURE: occupied by another operator",
+                    'join_as_operator FAILURE: occupied by another operator'
                 );
                 callback({ success: false });
             }
         } else {
-            status = "offline";
-            console.log("join_as_operator FAILURE: robot is not available");
+            status = 'offline';
+            console.log('join_as_operator FAILURE: robot is not available');
             callback({ success: false });
         }
         updateRooms();
     });
 
-    socket.on("signalling", (message) => {
+    socket.on('signalling', (message) => {
         if (robo_sock && oper_sock && io.sockets.adapter.rooms.get(ROOM)) {
-            socket.to(ROOM).emit("signalling", message);
+            socket.to(ROOM).emit('signalling', message);
         } else {
             console.log(
-                `signaling FAILURE: robo_sock=${robo_sock} oper_sock=${oper_sock} room=${io.sockets.adapter.rooms.get(ROOM)}`,
+                `signaling FAILURE: robo_sock=${robo_sock} oper_sock=${oper_sock} room=${io.sockets.adapter.rooms.get(ROOM)}`
             );
         }
     });
 
-    socket.on("bye", (role) => {
+    socket.on('bye', (role) => {
         console.log(`Received bye from ${role}`);
         if (socket.rooms.has(ROOM)) {
-            socket.to(ROOM).emit("bye");
+            socket.to(ROOM).emit('bye');
             if (socket.id == robo_sock) {
-                status = "offline";
+                status = 'offline';
                 robo_sock = undefined;
-                console.log("Robot disconnected");
+                console.log('Robot disconnected');
             }
             if (socket.id == oper_sock) {
-                status = "online";
+                status = 'online';
                 oper_sock = undefined;
-                console.log("Operator disconnected");
+                console.log('Operator disconnected');
             }
             socket.leave(ROOM);
         }
         updateRooms();
     });
 
-    socket.on("disconnect", () => {
+    socket.on('disconnect', () => {
         if (socket.id == robo_sock) {
-            status = "offline";
+            status = 'offline';
             robo_sock = undefined;
-            console.log("Robot disconnected");
+            console.log('Robot disconnected');
         }
         if (socket.id == oper_sock) {
-            status = "online";
+            status = 'online';
             oper_sock = undefined;
-            console.log("Operator disconnected");
+            console.log('Operator disconnected');
         }
         updateRooms();
     });
diff --git a/webpack.config.js b/webpack.config.js
index a7ab5ac5..fc956246 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -57,8 +57,8 @@ module.exports = (env) => {
                                 ? "index.html"
                                 : `${page}/index.html`,
                         chunks: [page],
-                    }),
-            ),
+                    })
+            )
         ),
         module: {
             rules: [


Reviews:
user: login: hello-robot-shehab
body: I love having Actions set up, thanks @hello-william!
 
I haven't tested the GitHub action itself - it looks good and shouldn't have issues though.

The pre-commit-config.yml works:
![image](https://github.com/user-attachments/assets/cb2fd03b-9370-4466-bf14-8d0d9d5e762c)

There are merge conflicts, so the branch needs to be rebased, or if you trust a FF go for it. This is good to go after the README update and thoughts on auto-commits, thanks!

Unrelated to JS linting, but to python:
- We have a .flake8 file, but flake8 is not in requirements.txt or requirements-dev.txt, it doesn't seem to interfere with the pre-commit check though.
- Would be nice to have a stronger styling guidelines to use mypy or python type-checking
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T19:43:55Z
user: login: hello-binit
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-06T20:30:20Z
user: login: hello-binit
body: I strongly feel the action should not commit and push fixes on its own. Failing out is sufficient. I recommend we don't merge this PR until this is changed.
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-05-06T20:30:49Z
user: login: hello-vinitha
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-08T23:11:30Z
user: login: hello-william
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T19:06:09Z
user: login: hello-binit
body: Thanks for getting this going @hello-william!!
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-09T21:32:49Z

Review comments:
diff_hunk: @@ -1,34 +1,78 @@
 name: pre-commit
 
 on:
+  # Run on push to master
   push:
     branches:
-      - main
       - master
+  # Run on pull request actions
   pull_request:
-    types: [opened, reopened, synchronize, review_requested, ready_for_review]
+    types: [opened, reopened, synchronize]
+  # Manual trigger
   workflow_dispatch:
 
+# Prevent parallel runs
 concurrency:
   group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
   cancel-in-progress: true
 
+# Global env vars
 env:
   PYTHON_VERSION: "3.10"
 
 jobs:
   pre-commit:
     runs-on: ubuntu-latest
-    if: ${{ !github.event.pull_request.draft }}
     steps:
-      - uses: actions/checkout@v4
-      - uses: actions/setup-python@v5
+      # Checkout code and keep creds for push
+      - name: Checkout repo
+        uses: actions/checkout@v4
+        with:
+          persist-credentials: true
+
+      # Setup Python
+      - name: Setup Python
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ env.PYTHON_VERSION }}
 
-      ## Run pre-commit and try to apply fixes
+      # Setup Node.js for JS hooks
+      - name: Use Node.js 21.x
+        uses: actions/setup-node@v3
+        with:
+          node-version: "21.x"
+
+      # Cache NPM deps
+      - name: Cache NPM
+        uses: actions/cache@v3
+        with:
+          path: ~/.npm
+          key: ${{ runner.os }}-npm-
+          restore-keys: |
+            ${{ runner.os }}-npm-
+
+      # Cache pip for Python hook installs
+      - name: Cache pip
+        uses: actions/cache@v3
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+          restore-keys: |
+            ${{ runner.os }}-pip-
+
+      # Install JS devDependencies
+      - name: Install devDependencies
+        run: npm install --legacy-peer-deps
+
+      # Run pre-commit hooks
       - name: Run pre-commit
         uses: pre-commit/action@v3.0.1
-      - name: Apply fixes from pre-commit
-        uses: pre-commit-ci/lite-action@v1.0.2
-        if: always()
+
+      # Commit & push any auto-fixes
+      - name: Commit auto-fixes
path: .github/workflows/pre-commit.yaml
user: login: hello-robot-shehab
body: I love the convenience of having the bot commit auto-formatting, but I'm wary of it; I've personally seen it removing imports or doing changes that were intended by the author that could then break the main branch. I'm okay with having this here, but we have to remember that it is here- thoughts, @hello-william, @hello-binit? The alternative is to fail the pre-commit action and have the user manually fix it. Thanks!
created_at: 2025-05-06T19:35:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,34 +1,78 @@
 name: pre-commit
 
 on:
+  # Run on push to master
   push:
     branches:
-      - main
       - master
+  # Run on pull request actions
   pull_request:
-    types: [opened, reopened, synchronize, review_requested, ready_for_review]
+    types: [opened, reopened, synchronize]
+  # Manual trigger
   workflow_dispatch:
 
+# Prevent parallel runs
 concurrency:
   group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
   cancel-in-progress: true
 
+# Global env vars
 env:
   PYTHON_VERSION: "3.10"
 
 jobs:
   pre-commit:
     runs-on: ubuntu-latest
-    if: ${{ !github.event.pull_request.draft }}
     steps:
-      - uses: actions/checkout@v4
-      - uses: actions/setup-python@v5
+      # Checkout code and keep creds for push
+      - name: Checkout repo
+        uses: actions/checkout@v4
+        with:
+          persist-credentials: true
+
+      # Setup Python
+      - name: Setup Python
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ env.PYTHON_VERSION }}
 
-      ## Run pre-commit and try to apply fixes
+      # Setup Node.js for JS hooks
+      - name: Use Node.js 21.x
+        uses: actions/setup-node@v3
+        with:
+          node-version: "21.x"
+
+      # Cache NPM deps
+      - name: Cache NPM
+        uses: actions/cache@v3
+        with:
+          path: ~/.npm
+          key: ${{ runner.os }}-npm-
+          restore-keys: |
+            ${{ runner.os }}-npm-
+
+      # Cache pip for Python hook installs
+      - name: Cache pip
+        uses: actions/cache@v3
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+          restore-keys: |
+            ${{ runner.os }}-pip-
+
+      # Install JS devDependencies
+      - name: Install devDependencies
+        run: npm install --legacy-peer-deps
+
+      # Run pre-commit hooks
       - name: Run pre-commit
         uses: pre-commit/action@v3.0.1
path: .github/workflows/pre-commit.yaml
user: login: hello-robot-shehab
body: Hey @hello-william, could I please ask you to add instructions in the README for running this locally? Thank you!

https://pre-commit.com/
```
pip install pre-commit
pre-commit run --all-files
```

created_at: 2025-05-06T19:36:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,34 +1,78 @@
 name: pre-commit
 
 on:
+  # Run on push to master
   push:
     branches:
-      - main
       - master
+  # Run on pull request actions
   pull_request:
-    types: [opened, reopened, synchronize, review_requested, ready_for_review]
+    types: [opened, reopened, synchronize]
+  # Manual trigger
   workflow_dispatch:
 
+# Prevent parallel runs
 concurrency:
   group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
   cancel-in-progress: true
 
+# Global env vars
 env:
   PYTHON_VERSION: "3.10"
 
 jobs:
   pre-commit:
     runs-on: ubuntu-latest
-    if: ${{ !github.event.pull_request.draft }}
     steps:
-      - uses: actions/checkout@v4
-      - uses: actions/setup-python@v5
+      # Checkout code and keep creds for push
+      - name: Checkout repo
+        uses: actions/checkout@v4
+        with:
+          persist-credentials: true
+
+      # Setup Python
+      - name: Setup Python
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ env.PYTHON_VERSION }}
 
-      ## Run pre-commit and try to apply fixes
+      # Setup Node.js for JS hooks
+      - name: Use Node.js 21.x
+        uses: actions/setup-node@v3
+        with:
+          node-version: "21.x"
+
+      # Cache NPM deps
+      - name: Cache NPM
+        uses: actions/cache@v3
+        with:
+          path: ~/.npm
+          key: ${{ runner.os }}-npm-
+          restore-keys: |
+            ${{ runner.os }}-npm-
+
+      # Cache pip for Python hook installs
+      - name: Cache pip
+        uses: actions/cache@v3
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+          restore-keys: |
+            ${{ runner.os }}-pip-
+
+      # Install JS devDependencies
+      - name: Install devDependencies
+        run: npm install --legacy-peer-deps
+
+      # Run pre-commit hooks
       - name: Run pre-commit
         uses: pre-commit/action@v3.0.1
-      - name: Apply fixes from pre-commit
-        uses: pre-commit-ci/lite-action@v1.0.2
-        if: always()
+
+      # Commit & push any auto-fixes
+      - name: Commit auto-fixes
path: .github/workflows/pre-commit.yaml
user: login: hello-binit
body: Yes, I strongly feel the action should not commit and push fixes on its own. Failing out is sufficient. I recommend we don't merge this PR until this is changed.
created_at: 2025-05-06T20:30:20Z
author_association: COLLABORATOR
diff_hunk: @@ -1,34 +1,78 @@
 name: pre-commit
 
 on:
+  # Run on push to master
   push:
     branches:
-      - main
       - master
+  # Run on pull request actions
   pull_request:
-    types: [opened, reopened, synchronize, review_requested, ready_for_review]
+    types: [opened, reopened, synchronize]
+  # Manual trigger
   workflow_dispatch:
 
+# Prevent parallel runs
 concurrency:
   group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
   cancel-in-progress: true
 
+# Global env vars
 env:
   PYTHON_VERSION: "3.10"
 
 jobs:
   pre-commit:
     runs-on: ubuntu-latest
-    if: ${{ !github.event.pull_request.draft }}
     steps:
-      - uses: actions/checkout@v4
-      - uses: actions/setup-python@v5
+      # Checkout code and keep creds for push
+      - name: Checkout repo
+        uses: actions/checkout@v4
+        with:
+          persist-credentials: true
+
+      # Setup Python
+      - name: Setup Python
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ env.PYTHON_VERSION }}
 
-      ## Run pre-commit and try to apply fixes
+      # Setup Node.js for JS hooks
+      - name: Use Node.js 21.x
+        uses: actions/setup-node@v3
+        with:
+          node-version: "21.x"
+
+      # Cache NPM deps
+      - name: Cache NPM
+        uses: actions/cache@v3
+        with:
+          path: ~/.npm
+          key: ${{ runner.os }}-npm-
+          restore-keys: |
+            ${{ runner.os }}-npm-
+
+      # Cache pip for Python hook installs
+      - name: Cache pip
+        uses: actions/cache@v3
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+          restore-keys: |
+            ${{ runner.os }}-pip-
+
+      # Install JS devDependencies
+      - name: Install devDependencies
+        run: npm install --legacy-peer-deps
+
+      # Run pre-commit hooks
       - name: Run pre-commit
         uses: pre-commit/action@v3.0.1
-      - name: Apply fixes from pre-commit
-        uses: pre-commit-ci/lite-action@v1.0.2
-        if: always()
+
+      # Commit & push any auto-fixes
+      - name: Commit auto-fixes
path: .github/workflows/pre-commit.yaml
user: login: hello-vinitha
body: I agree with @hello-binit 
created_at: 2025-05-08T23:11:29Z
author_association: COLLABORATOR
diff_hunk: @@ -1,34 +1,78 @@
 name: pre-commit
 
 on:
+  # Run on push to master
   push:
     branches:
-      - main
       - master
+  # Run on pull request actions
   pull_request:
-    types: [opened, reopened, synchronize, review_requested, ready_for_review]
+    types: [opened, reopened, synchronize]
+  # Manual trigger
   workflow_dispatch:
 
+# Prevent parallel runs
 concurrency:
   group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
   cancel-in-progress: true
 
+# Global env vars
 env:
   PYTHON_VERSION: "3.10"
 
 jobs:
   pre-commit:
     runs-on: ubuntu-latest
-    if: ${{ !github.event.pull_request.draft }}
     steps:
-      - uses: actions/checkout@v4
-      - uses: actions/setup-python@v5
+      # Checkout code and keep creds for push
+      - name: Checkout repo
+        uses: actions/checkout@v4
+        with:
+          persist-credentials: true
+
+      # Setup Python
+      - name: Setup Python
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ env.PYTHON_VERSION }}
 
-      ## Run pre-commit and try to apply fixes
+      # Setup Node.js for JS hooks
+      - name: Use Node.js 21.x
+        uses: actions/setup-node@v3
+        with:
+          node-version: "21.x"
+
+      # Cache NPM deps
+      - name: Cache NPM
+        uses: actions/cache@v3
+        with:
+          path: ~/.npm
+          key: ${{ runner.os }}-npm-
+          restore-keys: |
+            ${{ runner.os }}-npm-
+
+      # Cache pip for Python hook installs
+      - name: Cache pip
+        uses: actions/cache@v3
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+          restore-keys: |
+            ${{ runner.os }}-pip-
+
+      # Install JS devDependencies
+      - name: Install devDependencies
+        run: npm install --legacy-peer-deps
+
+      # Run pre-commit hooks
       - name: Run pre-commit
         uses: pre-commit/action@v3.0.1
path: .github/workflows/pre-commit.yaml
user: login: hello-william
body: i see this information already in the "Contributing" section (README.md line 329)
created_at: 2025-05-09T19:06:09Z
author_association: CONTRIBUTOR

PR comments:
user: login: hello-amal
created_at: 2024-05-22T00:06:11Z
body: At this point, CI is (rightly) failing due to the linting errors. But CI configuration is correct.
author_association: CONTRIBUTOR
user: login: wle8300
created_at: 2025-04-30T18:38:39Z
body: @hello-binit whew... ok i think this is g2g now

~~how do i add u as a reviewer?~~

crud... i was on my regular wle8300 github account... i must have switched my login at somepoint in vscode

i've added you as a reviewer
author_association: CONTRIBUTOR
user: login: hello-william
created_at: 2025-05-06T19:55:29Z
body: @hello-robot-shehab thx for the review!

i'll try to tackle this tmrw! 
author_association: CONTRIBUTOR
user: login: hello-william
created_at: 2025-05-08T22:55:22Z
body: crud...  sorry guys... i'll get to this first thing tmrw!
author_association: CONTRIBUTOR
user: login: hello-william
created_at: 2025-05-09T19:09:21Z
body: @hello-binit @hello-robot-shehab

i removed auto-fixing/auto-committing

it will exit 0, and provide a diff
author_association: CONTRIBUTOR
user: login: hello-robot-shehab
created_at: 2025-05-15T17:14:40Z
body: btw, GitHub Actions still seem to be failing for new PR's.
author_association: CONTRIBUTOR
user: login: hello-william
created_at: 2025-05-15T17:53:24Z
body: @hello-robot-shehab did you check the github action output?

there could be errors that need to be addressed before it will allow you to merge 

https://github.com/user-attachments/assets/b6caeaa1-4f02-4e76-811e-e471af5f2f6c


author_association: CONTRIBUTOR
user: login: hello-robot-shehab
created_at: 2025-05-15T17:58:13Z
body: Ah, thank you @hello-william! I was looking at the wrong tab, and didn't realize to go one tab up to see the pre-commit results. Good to know, this is helpful!
![image](https://github.com/user-attachments/assets/475faccf-330b-43c4-8505-695730803601)

author_association: CONTRIBUTOR
user: login: hello-william
created_at: 2025-05-15T18:00:47Z
body: @hello-robot-shehab np! :]

most of the linting rules are OOTB but i'm pretty sure vinitha/binit are cool with changing those lint rules if they're too burdensome... just lemme know and i can change those rules
author_association: CONTRIBUTOR
user: login: hello-robot-shehab
created_at: 2025-05-15T18:13:31Z
body: No problem, it's not too strict! We should have these on more repo's :fire: 

![image](https://github.com/user-attachments/assets/69950e06-dc6f-4cd4-9196-5221b98a526d)

author_association: CONTRIBUTOR
user: login: hello-william
created_at: 2025-05-15T18:15:16Z
body: ⚡️⚡️⚡️⚡️

> On May 15, 2025, at 11:13 AM, Shehab ***@***.***> wrote:
> 
> 
> hello-robot-shehab
>  left a comment 
> (hello-robot/stretch_web_teleop#45)
>  <https://github.com/hello-robot/stretch_web_teleop/pull/45#issuecomment-2884683217>
> No problem, it's not too strict! We should have these on more repo's 🔥
> 
> image.png (view on web) <https://github.com/user-attachments/assets/69950e06-dc6f-4cd4-9196-5221b98a526d>
> —
> Reply to this email directly, view it on GitHub <https://github.com/hello-robot/stretch_web_teleop/pull/45#issuecomment-2884683217>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/BRPYS2YMJUKEABQVCVVM7T326TKOFAVCNFSM6AAAAAB4ECGA5GVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDQOBUGY4DGMRRG4>.
> You are receiving this because you were mentioned.
> 


author_association: CONTRIBUTOR