From 258bfbb500702377433a1bd1cd3b7f4532455691 Mon Sep 17 00:00:00 2001 From: Vasanth Date: Fri, 16 Oct 2026 16:29:18 +0530 Subject: [PATCH] Add rpa-run-tab skill: Tebra-style Run tab in 5 minutes The Run tab from Tebra Auto Post, scrubbed and themable (Tebra Sky, TVL Teal, or a custom hex checked for contrast). The skill wires the real bot through tagged log-file lines and checks itself with a fake bot (complete, partial, stuck, crash) plus light and dark screenshots. Grill decisions R1-R14 are in PLAN.md, terms in GLOSSARY.md, and ADRs 0001-0003. Co-Authored-By: Claude Opus 5.5 --- .gitignore | 1 + CLAUDE.md | 2 +- GLOSSARY.md | 35 +- PLAN.md | 51 ++ ...0001-one-checkpoint-list-drives-run-tab.md | 11 + .../0002-bot-talks-through-tagged-log-file.md | 11 + .../0003-stuck-kills-no-restart-no-stop.md | 7 + rpa-run-tab/SKILL.md | 141 +++++ rpa-run-tab/templates/fake_bot.py | 31 + rpa-run-tab/templates/palette.py | 99 +++ rpa-run-tab/templates/rt.py | 36 ++ rpa-run-tab/templates/run_tab.html | 592 ++++++++++++++++++ rpa-run-tab/templates/run_tab.py | 345 ++++++++++ rpa-run-tab/templates/runner.py | 152 +++++ tests/README.md | 6 + tests/page_check_run_tab/conftest.py | 44 ++ tests/page_check_run_tab/test_run_tab_page.py | 101 +++ tests/test_run_tab.py | 49 ++ 18 files changed, 1712 insertions(+), 2 deletions(-) create mode 100644 docs/adr/0001-one-checkpoint-list-drives-run-tab.md create mode 100644 docs/adr/0002-bot-talks-through-tagged-log-file.md create mode 100644 docs/adr/0003-stuck-kills-no-restart-no-stop.md create mode 100644 rpa-run-tab/SKILL.md create mode 100644 rpa-run-tab/templates/fake_bot.py create mode 100644 rpa-run-tab/templates/palette.py create mode 100644 rpa-run-tab/templates/rt.py create mode 100644 rpa-run-tab/templates/run_tab.html create mode 100644 rpa-run-tab/templates/run_tab.py create mode 100644 rpa-run-tab/templates/runner.py create mode 100644 tests/page_check_run_tab/conftest.py create mode 100644 tests/page_check_run_tab/test_run_tab_page.py create mode 100644 tests/test_run_tab.py diff --git a/.gitignore b/.gitignore index 944df2b..0ad80fa 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__/ node_modules/ .venv/ .claude/worktrees/ +rpa-run-tab/logs/ diff --git a/CLAUDE.md b/CLAUDE.md index 7827378..f7c2c3f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,6 @@ # RPA SKILLS -Shared Claude skills for building RPA dashboards: `rpa-dashboard-no-ai` and `rpa-dashboard-ai`. See `PLAN.md`. +Shared Claude skills for building RPA dashboards: `rpa-dashboard-no-ai`, `rpa-dashboard-ai`, and `rpa-run-tab` (Tebra-style Run tab). See `PLAN.md`. ## Agent skills diff --git a/GLOSSARY.md b/GLOSSARY.md index ea2315a..9025a7d 100644 --- a/GLOSSARY.md +++ b/GLOSSARY.md @@ -1,5 +1,38 @@ # Glossary -**Run tab**: the full screen an operator uses to start and watch one bot run, modelled on Tebra Auto Post. It has the Trigger button, the input card and the run card. Built by its own skill. +**Run tab**: the full screen an operator uses to start and watch one bot run, modelled on Tebra Auto Post. It has the Trigger button, the input card and the run card. Built by the `rpa-run-tab` skill. **Run panel**: the smaller run section inside `rpa-dashboard-no-ai`: progress bar, steps and live log. It is a subset of the Run tab. Don't use the two names for the same thing. + +**Trigger button**: the single start button in the top bar. It has three states: +- off: "Upload a file to continue" +- on: "Trigger automation" +- going: "Running…" +There is no Stop or Pause. + +**Input card**: the Excel upload part of the Run tab: +- sample download +- drop zone +- file row +- sheet tabs +- preview of up to 200 rows, with password columns masked +- Clear file + +It is hidden for bots that take no input file. + +**Run card**: the progress part of the Run tab: +- progress bar with elapsed timer +- step list +- on-screen log +- checkpoint boxes + +**Checkpoint**: one named stage of a bot run, with a time limit in seconds (0 = no limit). The bot announces it with `[CPSTATE] active N` and `[CPSTATE] done N`. A project's checkpoint list drives the step list, the checkpoint boxes and the progress % on the Run tab. _Avoid_: "step" for a separate concept. In the Run tab, the steps are the checkpoints. + +**Stuck**: a checkpoint that has been active for longer than its time limit. A stuck run is killed and ends as failed (ADR-0003). + +**Outcome**: how a run ended, read from the bot's `__RUN_SUMMARY__` line: +- **completed** (green) +- **partial**: some items failed (amber) +- **failed**: crash, no summary, or stuck (red) + +**Fake bot**: a bundled script that prints the Run tab protocol lines, used to verify the page. The skill never runs the real bot. diff --git a/PLAN.md b/PLAN.md index c479f45..a2d1aec 100644 --- a/PLAN.md +++ b/PLAN.md @@ -113,3 +113,54 @@ rpa-dashboard-ai/ - asks the questions in order, - reports any existing frontend, - produces a working dashboard page that renders in light and dark. + +--- + +# Plan: `rpa-run-tab` skill (third skill) + +Goal: a skill that adds Tebra Auto Post's **Run tab** to any desktop RPA project in **5 minutes**. The look is the same as Tebra; only the colours are the user's choice. +- Source: `D:\Tebra_Auto_Post` `src/ui/main_window.py`. The Run tab code is at lines 1871–3979 (page) and 268–1142 (bridge). +- Also `run_app.py` (the `--run-automation` child process) and `core.py` (`wd_mark`). +- Take the tokenised accent from `D:\Tebra_Auto_Post_TVL`. Bundle a scrubbed template; never read D:\ at runtime. +- Terms are in `GLOSSARY.md`; decisions are in `docs/adr/0001`–`0003`. + +## Decisions (from the grill) + +| # | Question | Decision | +|---|---|---| +| R1 | Skill shape | A new standalone skill, `D:\RPA SKILLS\rpa-run-tab\`. Later, `rpa-dashboard-no-ai` points to it instead of keeping its own Run panel. | +| R2 | DB parts (batch chip, resume, clear-approval, roles) | **Left out.** No DB needed. Clear file just clears the file. | +| R3 | Stack | **Desktop only**: PyQt6 + QWebEngine. Runs from Python or a PyInstaller exe. | +| R4 | Input | Excel input card by default, with sheet tabs, a 200-row preview and password columns masked. **Hidden** for bots that take no file; the Trigger button is then ready straight away. | +| R5 | Steps vs checkpoints | **One checkpoint list** (name + time limit) drives the steps, the boxes and the progress %. See ADR-0001. | +| R6 | Stuck | Kill the process tree and end as failed "Stuck at X". No auto-restart. See ADR-0003. | +| R7 | On-screen log | The bot tags lines `[UI]`, `[UI:ok]`, `[UI:warn]`, `[UI:error]`. Errors and tracebacks always show. All raw lines go to the run log file. See ADR-0002. | +| R8 | Host | **Detect.** Add a tab to an existing PyQt web-view page or dashboard. Otherwise build a new window: Tebra top bar + Run tab, no sidebar. | +| R9 | Colours | Presets: 1) Tebra Sky, 2) TVL Teal, 3) Custom hex. A custom hex is turned into gradient and accent colours for light and dark, with a contrast check. ok/warn/bad and the log colours stay fixed. | +| R10 | Scope of the 5 minutes | Page **plus the real bot wired**. The skill reads the bot and proposes a checkpoint list for the user to confirm in one reply. It then adds the `[CPSTATE]`, `[UI]` and `__RUN_SUMMARY__` prints. | +| R11 | Endings | Green "Completed in …". Amber "Finished: N of M failed", with the failed items in the log. Red "Failed after …" or "Stuck at X". | +| R12 | Stop | **No Stop or Pause**, same as Tebra. Closing the window asks first, then kills the process tree. | +| R13 | Sample input | A headers-only sample built from the sheets and columns the bot reads, plus one fake row. The button is hidden if the skill can't tell. Never real data. | +| R14 | Verify | **Fake bot only.** It covers completed, partial and stuck runs in light and dark. The skill never presses Trigger on the real bot. | + +## Kept from Tebra as is +- Glass cards and the sky gradient. The Segoe UI font. The Consolas log with no timestamps. +- The dark toggle, saved to QSettings. +- The status dot: ready / running / done / error. +- Elapsed timers on the progress bar and on each checkpoint box. +- Progress only ever moves forward. Consecutive duplicate log lines are dropped. +- A double-run guard. The parent-death watcher in the child process. +- Python → page messages go through `window.__pyMsg` only, never also through `js_message.connect`, which delivers every message twice. + +## Tebra bugs not to copy +- A partial failure shows "Completed" at 100%. Fixed by R11. +- `STOP_REQUESTED` set only in the parent process. There is no Stop, and reload no longer fakes "Stopped by user". +- The checkpoint time limit in JS (300) and in Python (600) disagree. One list (R5) fixes this. +- Dead CSS and JS: `.top-ctrl-btn`, `.run-btn`, `showRerunModal`, `#rerun-mask`. + +## Runtime questions (keep to ≤3 for the 5-minute budget) +1. Colour: preset or custom hex. +2. Confirm the proposed checkpoint list, with names and time limits. +3. Excel input or no input. Skip this when the bot reading clearly answers it. + +The title and subtitle come from the project name. The user can edit them later. diff --git a/docs/adr/0001-one-checkpoint-list-drives-run-tab.md b/docs/adr/0001-one-checkpoint-list-drives-run-tab.md new file mode 100644 index 0000000..32db026 --- /dev/null +++ b/docs/adr/0001-one-checkpoint-list-drives-run-tab.md @@ -0,0 +1,11 @@ +# One checkpoint list drives the whole Run tab + +Tebra Auto Post keeps two overlapping lists: +- 8 **steps**, which move forward when known phrases appear in the log (`STEP_MARKERS`). +- 7 **checkpoints**, which move forward on `[CPSTATE]` lines and have time limits. + +The Run tab skill keeps one checkpoint list. The bot's `[CPSTATE] active|done N` lines move the step list, the checkpoint boxes and the progress % together. The screen still looks like Tebra. + +**Why:** there is one list to ask the user for, so the skill fits in 5 minutes. And a typo in a log phrase can no longer stall the progress bar without anyone noticing. + +**Cost:** the progress bar moves in whole checkpoints, not Tebra's finer per-phrase percentages. diff --git a/docs/adr/0002-bot-talks-through-tagged-log-file.md b/docs/adr/0002-bot-talks-through-tagged-log-file.md new file mode 100644 index 0000000..22a62e7 --- /dev/null +++ b/docs/adr/0002-bot-talks-through-tagged-log-file.md @@ -0,0 +1,11 @@ +# The bot talks to the Run tab through tagged lines in a log file + +The bot runs as a **separate process** with no Qt. The Run tab starts it with `--log ` and reads that file every 0.2 s. It does not read stdout. The bot prints: + +- `[CPSTATE] active N` / `[CPSTATE] done N`: checkpoint progress (see ADR-0001). +- `[UI] text`, `[UI:ok]`, `[UI:warn]`, `[UI:error]`: lines the operator sees. Error lines and tracebacks always show, even without a tag. Every raw line stays in the run log file. +- `__RUN_SUMMARY__{json}` as its last line. The outcome comes from this line, not from the exit code. If the line is missing, the run counts as failed, so a crash never shows green. + +**Why:** this comes from Tebra Auto Post. UI automation inside a Qt worker thread was unreliable (bug-094). A windowed PyInstaller child's stdout pipe is block-buffered, so log lines arrived in late bursts; reading the log file fixed that. Tagging lines saves each project from writing a table of phrase→friendly-text rules. + +**Conflict:** `rpa-dashboard-no-ai/templates/bot_runner.py` reads `stdout=PIPE`, which is the approach Tebra dropped. Fix it there, or point it at the Run tab skill's runner. diff --git a/docs/adr/0003-stuck-kills-no-restart-no-stop.md b/docs/adr/0003-stuck-kills-no-restart-no-stop.md new file mode 100644 index 0000000..8cdbd41 --- /dev/null +++ b/docs/adr/0003-stuck-kills-no-restart-no-stop.md @@ -0,0 +1,7 @@ +# A stuck run is killed and fails; no auto-restart, no Stop button + +When a checkpoint passes its time limit, the Run tab kills the bot's whole process tree and ends the run as failed: "Stuck at , run again". It does not restart. There is no Stop or Pause button. A run also ends early when the operator closes the window, which asks first and then kills the process tree. + +**Why:** Tebra Auto Post restarts a stuck bot up to 3 times. That is only safe because its SQL batch table lets a restarted bot skip work it already did. The Run tab skill has no DB (decision Q2), so a restart could do work twice, for example post a payment twice. Tebra removed Stop on purpose ("a run always goes to completion"), and the Run tab keeps the same look. + +**Reopen if:** a project's bot is rerun-safe (it skips items already done). Then auto-restart ×3 can come back as an option. diff --git a/rpa-run-tab/SKILL.md b/rpa-run-tab/SKILL.md new file mode 100644 index 0000000..0d15297 --- /dev/null +++ b/rpa-run-tab/SKILL.md @@ -0,0 +1,141 @@ +--- +name: rpa-run-tab +description: Adds a Tebra-style Run tab to a desktop RPA bot in about 5 minutes. The Run tab is a PyQt6 window (or a tab in an existing PyQt web page) with a Trigger button, an Excel input card (drop zone, sheet tabs, preview with masked passwords, sample download), a progress bar with a timer, a step list, a friendly live log, checkpoint boxes with time limits, and green/amber/red endings. It also wires the real bot to the page. Use when the user asks for a "Run tab", "run screen", "trigger screen", "start/run page for my bot", or "the Tebra run tab" for an RPA or automation project. For a whole dashboard (KPIs, report table), use rpa-dashboard-no-ai. +--- + +# RPA Run tab + +Build the Run tab, wire the real bot to it and check it with the fake bot. The whole job should take about 5 minutes. +The look is fixed. It is Tebra Auto Post's Run tab, and only the colours change. +Everything needed is in `templates/`. Never read the original Tebra projects. + +| File | What it is | +|---|---| +| `templates/run_tab.html` | The page. Its config comes from `run_tab.py`, and its theme is between `THEME:START` and `THEME:END`. Each part is fenced with `RUN-TAB:CSS`, `TOPBAR`, `MARKUP` and `JS` markers. | +| `templates/run_tab.py` | The PyQt6 window and bridge. It is also the bot's process (`--run-bot`, which loads no Qt). It holds the **CONFIG** block you fill in and `--selfcheck`. | +| `templates/runner.py` | Qt-free. It starts the bot, reads its log file every 0.2 s, turns lines into events, kills stuck runs and decides the ending. | +| `templates/rt.py` | The protocol helpers the bot calls: `checkpoint`, `checkpoint_done`, `ui`, `result`, `summary`. | +| `templates/fake_bot.py` | Prints the protocol for the endings complete, partial, stuck and crash. Used only by the self-check. | +| `templates/palette.py` | Theme: `sky`, `teal` or a brand hex. Use `--write` to put it into the page. It checks contrast. | + +The rules come from the repo's ADRs. Keep to them: +- One checkpoint list drives the steps, the boxes and the progress %. +- The bot talks only through tagged lines in a log file. +- A stuck checkpoint kills the run, and the run fails. +- There is no auto-restart and no Stop or Pause button. +- There is no database, no resume and no roles. + +## 1. Scan (about 1 minute, ask nothing yet) + +**Never run the bot.** Real bots act on live systems. + +1. **Bot entry point.** + - Look for a `main(...)` function, an `if __name__ == "__main__"` script, or a `run_*` function. + - Note its loop over input rows or items. Those become the summary's `total` and `failed`. + - Note its big stages, such as sign in, open a page, process rows, export. Those become the checkpoints. +2. **Input.** + - Does the bot read an Excel file (`openpyxl`, `pandas.read_excel`, `xlrd`)? + - If yes, note the sheet names and column names it reads, for `SAMPLE_SHEETS`. + - No Excel file means `HAS_INPUT = False`. +3. **Host.** Search for `QWebEngineView`, `setHtml` or a `.html` page loaded by PyQt, or an `rpa-dashboard-no-ai` `dashboard.html`. If you find one, the Run tab becomes a tab in it (step 4b). Otherwise it gets its own window (step 4a). +4. **Processes.** Note any extra programs the bot starts and that must die with it, such as `chromedriver.exe` or a desktop app. These go in `KILL_ALSO`. + +## 2. Ask once (one message, at most 3 questions) + +Send the scan result and these questions in one message, then wait: +1. **Colour:** + - 1) Tebra Sky (blue) + - 2) TVL Teal (green) + - 3) Custom: send one brand hex +2. **Checkpoints:** propose 3–8, each with a name of 2–3 plain words and a time limit, for example `Sign in, max 5 min`. Use `no limit` for long loops over rows. The user confirms or edits the list. +3. **Input:** "Excel input, or no input file?" Skip this question when the scan already answered it. + +Default the title and subtitle from the project name, for example `Run automation` and `Upload the input Excel and start `. Don't ask about them. + +## 3. Build + +1. Copy `run_tab.html`, `run_tab.py`, `runner.py` and `fake_bot.py` into `/run_tab/`. +2. Copy `rt.py` there and next to the bot's entry file. +3. Fill the **CONFIG** block at the top of `run_tab/run_tab.py`: + - `TITLE`, `SUBTITLE` + - `BOT`: `"bot.py"` relative to the project root, or `"package.module:function"` + - `HAS_INPUT`, `INPUT_HINT` + - `CHECKPOINTS` + - `SAMPLE_SHEETS` + - `KILL_ALSO` + - `APP_ID`: the project name, no spaces +4. Apply the theme: `python /templates/palette.py --write /run_tab/run_tab.html`. + - It must print PASS for every row. + - If a row fails, tell the user and suggest a darker hex. +5. Make sure `openpyxl`, `PyQt6` and `PyQt6-WebEngine` are in the project's requirements. + +## 4. Wire the bot + +Keep the bot's logic as it is. Only add these lines: + +```python +import rt + +def main(excel_path): # BOT = "bot:main"; the Run tab passes the Excel path + rt.checkpoint(1); rt.ui("Signing in"); ...; rt.ui("Signed in", "ok"); rt.checkpoint_done(1) + failed = [] + rt.checkpoint(2) + for i, row in enumerate(rows, start=2): + try: process(row) + except Exception as e: failed.append((f"Row {i}", str(e))); rt.ui(f"Row {i} failed", "warn") + rt.checkpoint_done(2) + return rt.result(total=len(rows), failed=failed) +``` + +- **Checkpoint numbers** are 1-based positions in `CHECKPOINTS`. A loop may go back to an earlier checkpoint for the next item; the later boxes reset and the bar never moves back. +- **Returning a summary.** A plain script with no entry function prints `rt.summary(total, failed)` as its last line instead. If no summary arrives, the run counts as **failed**. +- **What the operator sees.** Only `[UI]` lines and error lines reach the screen. Everything else goes only to `logs/run_