From 3f935ee183e69e73dfad39641655cf71050df464 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Fri, 2 Oct 2026 14:24:13 +1300 Subject: [PATCH] Script buttons, live mode and macro recorder pages (PRs #1219-#1225, #1227, #1228, pending); report-arrow submenu fix (#1218, pending) New pages script_buttons, assistant_live_mode, macro_recorder, linked from the sidebar, scripting, mcp_server and ai_assistants. ai_assistants: the 29 Sep section no longer says 'Not merged yet'. --- _Sidebar.md | 6 + ai_assistants.md | 21 ++- assistant_live_mode.md | 222 ++++++++++++++++++++++++++++++ drawing_faster.md | 12 ++ macro_recorder.md | 167 +++++++++++++++++++++++ mcp_server.md | 13 ++ script_buttons.md | 303 +++++++++++++++++++++++++++++++++++++++++ scripting.md | 26 ++++ 8 files changed, 769 insertions(+), 1 deletion(-) create mode 100644 assistant_live_mode.md create mode 100644 macro_recorder.md create mode 100644 script_buttons.md diff --git a/_Sidebar.md b/_Sidebar.md index 609cf48..d631f54 100644 --- a/_Sidebar.md +++ b/_Sidebar.md @@ -157,6 +157,12 @@ **[Connecting an AI assistant](ai_assistants)** — setup for Claude, Copilot, Gemini, Codex, Cursor, LM Studio +**[Script buttons](script_buttons)** — stored scripts with an icon, by hand or by an assistant _(pending)_ + +**[Live mode](assistant_live_mode)** — an assistant working in the open project while you watch _(pending)_ + +**[Macro recorder](macro_recorder)** — record a task by hand, for an assistant to script _(pending)_ + **[Development Roadmap](development_roadmap)** **[Vision](vision)** — _proposal, under discussion_ diff --git a/ai_assistants.md b/ai_assistants.md index 90dac91..d964d12 100644 --- a/ai_assistants.md +++ b/ai_assistants.md @@ -230,7 +230,7 @@ The server speaks MCP over standard input and output. --- -## Not merged yet +## Added on 29 September 2026 Four changes make this simpler. All four merged on 29 September 2026, so they are in builds made after that (on Windows, nightlies newer than @@ -278,6 +278,24 @@ It also tells you, in bold, when something is missing: | *Python est introuvable sur cet ordinateur* | the Python the setup names is not there. On Windows, run the QElectroTech installer again and tick *Python pour l'assistant IA*, or install Python; elsewhere, install Python 3 from your system's packages | | *Python n'est peut-être pas installé* (Windows) | only the Microsoft Store shortcut answers to `python`, which opens the Store instead of running the server | +## Coming next: buttons, live mode, recordings + +> **Status: pending.** Described on their own pages, each in open pull +> requests ([#1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219)–[#1225](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1225), +> [#1227](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1227), +> [#1228](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1228)). +> None works until they are merged. + +- **[Script buttons](script_buttons)**: ask the assistant for a button; it + writes the script, tests it on a copy of a project, and stores it with an + icon. You press it. +- **[Live mode](assistant_live_mode)**: with a setting turned on and a warning + accepted at each start, the assistant works in the project you have open, + one Ctrl+Z per action. +- **[Macro recorder](macro_recorder)**: do the task once by hand while + recording, paste the request, and the assistant writes a script it has + checked does the same. + ## ChatGPT, and Claude or Copilot in a web browser These reach a server only through the internet, from their own computers. @@ -290,3 +308,4 @@ still use the server's reading tools on a project you upload to it. See - **[MCP server](mcp_server)**: every tool and setting - **[JavaScript Scripting](scripting)**: what edits run underneath +- **[Script buttons](script_buttons)**, **[Live mode](assistant_live_mode)**, **[Macro recorder](macro_recorder)**: pending diff --git a/assistant_live_mode.md b/assistant_live_mode.md new file mode 100644 index 0000000..1246386 --- /dev/null +++ b/assistant_live_mode.md @@ -0,0 +1,222 @@ +# Live mode: an AI assistant working in the open project + +Normally an AI assistant connected through the **[MCP server](mcp_server)** +works on files: it reads a `.qet`, tests changes on copies, and never touches +the drawing you have open. **Live mode** adds a second way of working: the +assistant on one screen, QElectroTech on the other, and each thing it does +happens in front of you, in the project you have open — where you can watch +it, refuse it, undo it, or carry on by hand. + +> **Status: pending.** Nothing on this page is merged yet: +> +> | PR | What it adds | Builds on | +> |---|---|---| +> | [#1222](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1222) | the setting, the startup warning, the status-bar indicator, running scripts live | [#1221](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1221) ([script buttons](script_buttons)) | +> | [#1223](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1223) | the *Assistant* panel, ask-first, the allowed commands, the screenshot | #1222 | +> | [#1225](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1225) | the `qet_live_*` MCP tools | [#1224](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1224) | +> +> Check those PRs before trying any of this against your own build. The +> proposal is +> [discussion #1226](https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/1226). + +Menu and option names are given in French, as QElectroTech shows them until +the translations are updated, with an English gloss in italics. + +--- + +## The two ways an assistant works + +| | Headless (the usual way) | Live | +|---|---|---| +| works on | `.qet` files and copies of them | the project open in your QElectroTech | +| QElectroTech running? | no — started in the background for each call | yes, your own window | +| MCP tools | `qet_*`, `qet_script_*` | `qet_live_*` only | +| what you must switch on | `QET_ENABLE_SCRIPTING=1` | that, **and** the live setting, **and** the warning at this start | +| undo | nothing of yours changed | one Ctrl+Z per assistant action | + +A script tested headless runs the same way live; only where it runs changes. +The tools are kept apart so one can never be taken for the other. + +--- + +## Switching it on: three switches + +1. **The MCP server** is started with `QET_ENABLE_SCRIPTING=1`, as for the + editing tools (see [Scripting gate](mcp_server#scripting-gate)). +2. **The setting.** In **Configurer QElectroTech > Général** (*Settings > + General*): *Autoriser un assistant IA à agir sur le projet ouvert (mode + direct)* (*Allow an AI assistant to act on the open project (live mode)*). + Off by default. It takes effect at the next start; unticking it cuts the + connection at once. +3. **The warning, at every start.** While the setting is on, each time + QElectroTech starts it shows, before anything can connect: + + > *Le mode direct est activé : un assistant IA connecté pourra exécuter des + > scripts sur le projet ouvert. Chaque action s'annule d'un Ctrl+Z, et le + > bouton « Arrêter » de la barre d'état coupe la connexion.* + > + > (*Live mode is on: a connected AI assistant will be able to run scripts on + > the open project. Each action is undone with Ctrl+Z, and the "Stop" button + > on the status bar cuts the connection.*) + + | Button | Does | + |---|---| + | *Continuer* (*Continue*) | opens the connection for this session | + | *Pas pour cette session* (*Not this session*) | stays closed until the next start | + | *Désactiver* (*Turn off*) | stays closed and turns the setting off | + + So a setting you forgot about can never leave the door open silently. + +With the setting off, QElectroTech opens nothing at all and behaves exactly as +it does without this feature; the `qet_live_*` tools answer that live mode is +off and do nothing. When they cannot connect, they say which of the three +switches is missing. + +--- + +## While the assistant is connected + +### The status bar + +Shows *Mode direct : en attente d'un assistant* (*Live mode: waiting for an +assistant*) or *Mode direct : assistant connecté* (*assistant connected*), then +the last thing it did, with ✓ or ✗ and the time. Hover it for the error, if +there was one. + +**Arrêter** (*Stop*) beside it cuts the connection for the rest of the session. + +### The Assistant panel + +> **Status: pending** — [PR #1223](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1223). + +A panel called **Assistant** opens on the right while live mode is open. It +lists every action, newest first: the time, ✓ or ✗, and its undo step's name. +Hover an entry, or double-click it, for the details: the error, what the +script logged, and the script itself. + +At the top: *Demander avant d'exécuter un script écrit par l'assistant* (*Ask +before running a script the assistant wrote*), **ticked at every start**. While +it is ticked, a script the assistant wrote on the spot is shown to you first, +in a box titled *L'assistant veut exécuter un script* (*The assistant wants to +run a script*): + +| Button | Does | +|---|---| +| *Exécuter* (*Run*) | runs it | +| *Refuser* (*Refuse*) | nothing happens; the assistant is told you refused | +| *Toujours pour cette session* (*Always this session*) | runs it and stops asking until the next start | + +Stored scripts — the **[script buttons](script_buttons)** you already have — +run without asking: you put them there. + +### Undo + +Each assistant action is **one undo step**, named *Assistant : <what it +did>*, in the same undo history as your own work. Ctrl+Z takes it back. + +The assistant can undo too (`qet_live_undo_last`), but **only its own last +step**. If the newest step is something you did, it is refused: what you do by +hand stays yours to undo. + +--- + +## What the assistant can do + +> **Status: pending** — [PR #1225](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1225) +> (and #1223 for the commands and the screenshot). + +| Tool | Does | Needs `QET_ENABLE_SCRIPTING=1` | +|---|---|---| +| `qet_live_status` | is QElectroTech there and live mode open; the project and sheet on screen, how many sheets, what is selected, the last undo step; the stored scripts; whether a [macro recording](macro_recorder) is under way | no | +| `qet_live_run_script` | runs script text on the open project (asks you first, see above); returns what it logged, its error, and the undo step's name | yes | +| `qet_live_run_stored` | presses one of your stored script buttons, by its id | yes | +| `qet_live_command` | runs one editor command from a fixed list (below) | no | +| `qet_live_show_folio` | shows another sheet of the open project | no | +| `qet_live_undo_last` | undoes the newest step, only if it was the assistant's | no | +| `qet_live_screenshot` | an image of the sheet on screen, so the assistant sees what you see | no | + +### The commands it may use + +Only commands that open no window, so nothing can end up waiting for an +answer nobody gives. Everything else — saving, deleting, exporting, printing — +is refused; for edits it runs a script, which you can undo. + +| Command id (`diagrameditor.…`) | | +|---|---| +| `select_all`, `select_nothing`, `select_invert`, `select_all_conductors`, `select_all_text_fields` | selection | +| `zoom_in`, `zoom_out`, `zoom_content`, `zoom_fit`, `zoom_reset` | view | +| `rotate_selection`, `rotate_texts`, `snap_selection_to_grid` | arrange | +| `group_selection`, `ungroup_selection` | [groups](grouping_items) | +| `conductor_reset` | redraw the selected wires' path | + +### What it cannot do + +- **Click on the screen.** Clicking at coordinates breaks at every layout + change and can be steered by anything drawn on a sheet. The assistant acts + only through the same calls a script button uses. +- **Open a dialog.** `qet.showMessage()` in a live script goes to the log + instead of opening a box. +- **Run two things at once.** One request at a time; a second one meanwhile is + answered "busy". A script still stops after 30 seconds. +- **Reach you over the network.** The connection is a local socket (a named + pipe on Windows), on your own machine only. + +--- + +## How the assistant finds QElectroTech + +When you press *Continuer*, QElectroTech adds the connection's name and a +random token to `qet-assistant.json` (see +[script buttons](script_buttons#qet-assistantjson)), readable only by you, and +removes them on *Arrêter* or when it closes. The MCP server reads them from +there; a connection without the token is closed. + +The token keeps out other users of the computer and stale connections. A +program already running as you could read your projects anyway, which is why +what you can see — the indicator, the panel, ask-first, undo — matters more +than the token. + +--- + +## The risk, stated plainly + +Live mode is the one place an assistant changes the project you have open. The +risk it adds: **text inside a project you received** (a label, a note, a +title-block field) could try to steer the assistant into editing your drawing. +The answers are ask-first for anything the assistant writes itself, the log, +and one Ctrl+Z per action. If you do not need it, leave the setting off. + +--- + +## A session, start to finish + +1. Tick the live setting, restart QElectroTech, press *Continuer*. The status + bar says *en attente d'un assistant*; the Assistant panel opens. +2. Open your project. In the assistant's chat: *"number the wires on the sheet + I'm looking at, starting at 100"*. +3. The assistant calls `qet_live_status`, sees the project and sheet, and may + take a `qet_live_screenshot`. +4. It writes a script and sends it with `qet_live_run_script`. The ask-first + box shows it; you press *Exécuter*. +5. The wires are numbered; the panel shows *Assistant : …* with ✓. + Not what you wanted? Ctrl+Z. +6. **Arrêter** when you are done. + +--- + +## Limitations + +- **macOS has not been tested.** Linux, and a Windows build under Wine with a + Windows-side client, have. +- **No questions back.** A live script cannot ask you for a value; the + assistant asks in its chat instead. + +--- + +## See also + +- **[Script buttons](script_buttons)** — the stored scripts live mode can press +- **[Macro recorder](macro_recorder)** — show the assistant a task instead of describing it +- **[MCP server](mcp_server)** and **[Connecting an AI assistant](ai_assistants)** +- **[JavaScript Scripting](scripting)** — what a script can do +- [Discussion #1226](https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/1226) — the proposal diff --git a/drawing_faster.md b/drawing_faster.md index 72bc26d..2606137 100644 --- a/drawing_faster.md +++ b/drawing_faster.md @@ -93,6 +93,18 @@ A project that has none yet gets the common collection's **Coming arrow** and **Going arrow**. If the common collection isn't available either, the submenu is hidden. It is also hidden on a read-only sheet. +> **Status: pending.** The paragraph below describes +> [PR #1218](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1218), +> not yet merged. Until it lands, current builds show the bug it fixes +> ([#1210](https://github.com/qelectrotech/qelectrotech-source-mirror/issues/1210)): +> once you place a Coming arrow, the Going arrow drops out of the submenu +> (and the other way round), and comes back only after closing the project +> without saving. + +With #1218 the submenu always lists the standard **Coming arrow** and +**Going arrow**, after the report symbols the project already uses, and each +name appears once. Placing one arrow no longer hides the other. + For what a sheet report does once placed, see **[Linking wires across pages](folio_links)**. diff --git a/macro_recorder.md b/macro_recorder.md new file mode 100644 index 0000000..69bacee --- /dev/null +++ b/macro_recorder.md @@ -0,0 +1,167 @@ +# Macro recorder + +Do a task once by hand in QElectroTech, with recording on. Then hand the +recording to an AI assistant, which turns it into a general, tested +**[script button](script_buttons)** — "rotate the selected coils half a +turn" rather than "rotate KA1 and KA2". + +> **Status: pending.** Nothing on this page is merged yet: +> +> | PR | What it adds | Builds on | +> |---|---|---| +> | [#1227](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1227) | recording in QElectroTech: start, stop, the files, the status bar, the request to paste | [#1223](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1223) | +> | [#1228](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1228) | the `qet_recording_*` MCP tools | [#1225](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1225) | +> +> Both sit at the end of the [script buttons](script_buttons) series. Check +> the PRs before trying any of this against your own build. + +> **Not the same "macros" as templates.** QElectroTech's +> **[templates](templates)** — reusable blocks of symbols — live in a folder +> called `macros`. The macro recorder has nothing to do with them: it records +> *what you do*, and its result is a script. + +Menu and option names are given in French, as QElectroTech shows them until +the translations are updated, with an English gloss in italics. + +--- + +## Why a recording, and not a replay + +Describing a drawing task in words to an assistant is slow and easy to get +wrong. Showing it is quicker. But replaying your mouse clicks would break as +soon as anything on the sheet moved, so the recorder does not keep clicks. It +keeps **what changed**, step by step, and the whole project before and after. +The assistant writes a script from that, and checks the script reproduces +exactly the change you made. + +QElectroTech cannot send anything to an assistant itself: the assistant asks, +QElectroTech answers. So the recording is saved where the assistant's +**[MCP server](mcp_server)** can read it, and you hand it over with one paste. + +--- + +## Recording + +> **Status: pending** — [PR #1227](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1227). + +1. Open the project and select what the task starts from (the selection is + recorded too). +2. **Projet > Scripts > Enregistrer une macro** (*Project > Scripts > Record a + macro*). It is also a command in command search (**Ctrl+Shift+M**) and on + the **S** shortcut bar if you add it. +3. Do the task. The status bar shows *● Enregistrement : N étape(s)* + (*Recording: N steps*) with an **Arrêter** (*Stop*) button. +4. Stop: **Arrêter**, or the same menu entry, which is ticked while recording. + +A box, *Macro enregistrée* (*Macro recorded*), gives the recording's name +(*Macro du 02/10/2026 14:30*), its number of steps and its folder: + +| Button | Does | +|---|---| +| *Copier la demande pour l'assistant* (*Copy the request for the assistant*) | copies a ready-made request to paste into the assistant's chat | +| *Ouvrir le dossier* (*Open the folder*) | opens the recording's folder | +| *Fermer* (*Close*) | closes the box; the recording stays saved | + +Recording needs no setting: it only writes files. Turning it into a script +does — see below. + +### What counts as a step + +Every entry the task adds to the undo history (*Annulations*, *Undo* panel) is +one step: its name as the Undo panel shows it, which sheet, what +was selected after it, and the sheet as it was after it. Because steps come +from the undo history, any command QElectroTech has is recorded with nothing +to teach the recorder. + +- **An undo during the recording** is recorded as a step too. +- **Several moves of the same item in a row** merge into one step, as they do + in the undo history. The before-and-after result is still exact. +- **Closing the project while recording** stops it and keeps the steps so far, + but there is then no "after" project, and the recording says so. + +### Where it is saved + +In the `recordings` folder of your QElectroTech data folder, one folder per +recording: + +| System | Folder | +|---|---| +| Linux | `~/.local/share/QElectroTech/QElectroTech/recordings/` | +| Windows | `%APPDATA%\QElectroTech\QElectroTech\recordings\` | +| macOS | `~/Library/Application Support/QElectroTech/QElectroTech/recordings/` | + +``` +recordings// + recording.json name, project, start and stop time, the steps + before.qet the whole project when you started recording + after.qet the whole project when you stopped + steps/003.xml the sheet the step happened on, as it was after step 3 +``` + +`qet-assistant.json` (see +[script buttons](script_buttons#qet-assistantjson)) lists the recordings and +whether one is under way; in **[live mode](assistant_live_mode)**, +`qet_live_status` says so too. + +On a very large project, saving `before.qet` and `after.qet` can take a few +seconds, as saving the project does — at start and stop only, not at each +step. + +--- + +## Turning it into a script + +> **Status: pending** — [PR #1228](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1228). + +Paste the copied request into the assistant's chat. It names the recording and +asks the assistant to read it with `qet_recording_read`, write a script that +does the same **in general** (on the selected items rather than on those +particular ones), check it with `qet_recording_check` until it matches, then +offer it as a button with `qet_script_install`. You can add to it: *"…and make +it work on every sheet"*. + +| Tool | Does | Needs `QET_ENABLE_SCRIPTING=1` | +|---|---|---| +| `qet_recording_list` | the recordings, newest first: id, name, steps, project | no | +| `qet_recording_read` | one recording as structured changes — each step's name, sheet, selection and what changed on the sheet ("element KA1 moved by (20, 0)", "wire added between …") — and the overall change from before to after | no | +| `qet_recording_check` | runs a script on a copy of `before.qet`, starting from the same sheet and selection you had, and compares the result with `after.qet`: **matches**, or what differs | yes | +| `qet_recording_remove` | deletes one recording | yes | + +`qet_recording_check` is what makes "the script does what I did" a measured +fact rather than the assistant's guess. A rotation by the wrong angle, a +script that does nothing, or one that fails — each is reported, the last with +the line that failed. + +--- + +## Worked example + +1. Select the two coils on a sheet. +2. **Projet > Scripts > Enregistrer une macro**. +3. Rotate the selection twice (Space, Space). +4. **Arrêter** → *Copier la demande pour l'assistant* → paste into the chat. +5. The assistant reads 2 steps, writes "rotate every selected symbol by 180°", + and `qet_recording_check` reports a match. A first try at 90° would be + reported a quarter turn off. +6. It installs the script; a **Scripts** toolbar button appears. Next time, + select any symbols and click it. + +--- + +## Limitations + +- **One project per recording.** +- **No clicks or positions replayed** — on purpose, see above. +- **QElectroTech does not call an assistant itself.** That would mean API + keys, network access and a choice of provider inside QElectroTech: a + different project. +- **macOS has not been tested.** + +--- + +## See also + +- **[Script buttons](script_buttons)** — where the resulting script ends up +- **[Live mode](assistant_live_mode)** — the assistant acting in the open project +- **[MCP server](mcp_server)** and **[Connecting an AI assistant](ai_assistants)** +- **[JavaScript Scripting](scripting)** diff --git a/mcp_server.md b/mcp_server.md index 98a21b9..e1fe22f 100644 --- a/mcp_server.md +++ b/mcp_server.md @@ -244,6 +244,17 @@ from before the setting existed need nothing. \* Needs `QET_ENABLE_SCRIPTING=1`. +> **Status: pending.** Three more groups of tools are in open pull requests, +> each described on its own page: +> +> | Tools | Page | PR | +> |---|---|---| +> | `qet_script_api`, `qet_script_test`, `qet_script_install`, `qet_script_list`, `qet_script_read`, `qet_script_remove`, `qet_about` | [Script buttons](script_buttons#letting-an-ai-assistant-write-the-script) | [#1224](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1224) | +> | `qet_live_status`, `qet_live_run_script`, `qet_live_run_stored`, `qet_live_command`, `qet_live_show_folio`, `qet_live_undo_last`, `qet_live_screenshot` | [Live mode](assistant_live_mode#what-the-assistant-can-do) | [#1225](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1225) | +> | `qet_recording_list`, `qet_recording_read`, `qet_recording_check`, `qet_recording_remove` | [Macro recorder](macro_recorder#turning-it-into-a-script) | [#1228](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1228) | +> +> None of them works until its PR is merged. + --- ## Worked examples @@ -460,6 +471,8 @@ regression in the thing under test, not a missing switch. - **[Connecting an AI assistant](ai_assistants)** — setup for each assistant - **[JavaScript Scripting](scripting)** — the `qet.*` engine `qet_edit` and `qet_query` drive underneath +- **[Script buttons](script_buttons)**, **[Live mode](assistant_live_mode)**, + **[Macro recorder](macro_recorder)** — the pending script, live and recording tools - **[The project database](project_database)** — what `qet_query` reads - **[CLI Reference](cli_reference)** — the export flags `qet_export` wraps - **[Automating QElectroTech](api_reference)** — the file-format and diff --git a/script_buttons.md b/script_buttons.md new file mode 100644 index 0000000..4addab9 --- /dev/null +++ b/script_buttons.md @@ -0,0 +1,303 @@ +# Script buttons + +Keep a JavaScript script in QElectroTech, give it an icon and a shortcut, and +run it from a button, a menu, the shortcut bar or command search — instead of +picking the file again every time. You can write the script yourself, or let +an AI assistant write, test and store it through the +**[MCP server](mcp_server)**. Both end in the same place: a file in your +scripts folder, which QElectroTech turns into a button. + +> **Status: pending.** Nothing on this page is merged yet; the series starts +> with [PR #1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219). Each section names +> its own pull request; check it before trying any of this against your own +> build. The whole series: +> +> | PR | What it adds | Builds on | +> |---|---|---| +> | [#1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219) | `qet.currentFolio()`, `qet.apiSignatures()`, one undo step per run | — | +> | [#1220](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1220) | stored scripts, the *Scripts* menu and toolbar | #1219 | +> | [#1221](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1221) | the script manager window | #1220 | +> | [#1224](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1224) | MCP tools to write, test and store scripts | — | +> +> The proposal and its open questions are in +> [discussion #1226](https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/1226). +> The same series continues with **[live mode](assistant_live_mode)** and the +> **[macro recorder](macro_recorder)**. + +Menu and option names are given in French, as QElectroTech shows them until +the translations are updated, with an English gloss in italics. + +--- + +## Why this exists + +**[JavaScript Scripting](scripting)** already lets a script read a project, +edit it with real undo, and export it. But from the editor, *Exécuter un +script…* (*Run script*) asks for a file every time, and a script cannot tell +which sheet you are looking at. So a repeated task — put a revision note on +this sheet, renumber the selected wires, rotate the selected coils — stays a +chore. Script buttons make a script a command like any other. + +## Before you start: scripting must be on + +Scripts are **off by default** +([PR #984](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/984)). +A script runs with your rights: it can read and change the open project and +write files. The setting is in **Configurer QElectroTech > Général** (*Settings +> General*): *Autoriser l'exécution de scripts JavaScript* (*Allow running +JavaScript scripts*). If it is off, the first time you press a script button +QElectroTech asks whether to turn it on. Nothing on this page gets around that +switch. + +--- + +## The scripts folder + +> **Status: pending** — [PR #1220](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1220). + +Each script is one `.js` file in the `scripts` folder of your QElectroTech +data folder: + +| System | Folder | +|---|---| +| Linux | `~/.local/share/QElectroTech/QElectroTech/scripts/` | +| Windows | `%APPDATA%\QElectroTech\QElectroTech\scripts\` | +| macOS | `~/Library/Application Support/QElectroTech/QElectroTech/scripts/` | + +If you start QElectroTech with `--data-dir`, the folder moves with it. +**Projet > Scripts > Ouvrir le dossier des scripts** (*Project > Scripts > +Open the scripts folder*) opens it, creating it if needed. + +QElectroTech watches the folder. Drop a script in and its button appears +straight away; delete it and the button, its menu entry and its shortcut go. +No restart, and nothing to register. + +Scripts are yours, not the project's: nothing is added to the `.qet` file, and +a project you receive cannot bring a script with it. + +### The header + +The top of the file says how the button looks. One file holds both, so there +is nothing to keep in step and one file to share: + +```js +// ==QETScript== +// @name Add revision note +// @icon note.svg +// @tooltip Puts a "Rev A" note on the sheet you are looking at +// @shortcut Ctrl+Alt+R +// @context canvas +// @api 1 +// ==/QETScript== +var f = qet.currentFolio(); +qet.addText(f, "Rev A", 40, 40); +``` + +| Key | Required | Meaning | +|---|---|---| +| `@name` | **yes** | the button's text, and the name shown in menus, command search and the undo history | +| `@icon` | no | a picture file next to the script (`note.svg`, `note.png`), or `builtin:` for an icon from QElectroTech's theme. Left out: a tile with the name's initials | +| `@tooltip` | no | the text shown when you hover the button | +| `@shortcut` | no | a keyboard shortcut, written as Qt writes them (`Ctrl+Alt+R`). A shortcut you set in the shortcut settings wins over it | +| `@context` | no | when the button is usable — see the next table. Default `canvas` | +| `@api` | no | the header version; only `1` exists | + +| `@context` | The button works when… | +|---|---| +| `canvas` | a project is open (always) | +| `selection` | something is selected on the sheet | +| `conductor` | at least one wire is selected | + +Without an open project every script button is greyed out. + +**A wrong header is refused, not ignored.** An unknown key (`@shortcutt`), a +missing `@name`, an unknown `@context` or an `@api` other than `1` means no +button. The file is listed greyed in **Projet > Scripts** as *Ignoré : +broken.js: unknown header key @shortcutt* (*Ignored*), so you can see which +line is wrong. A misspelt shortcut that silently did nothing would be harder +to find. + +A file name becomes the script's id: `add-revision-note.js` is +`diagrameditor.script.add-revision-note` in the shortcut settings. + +--- + +## Running a script + +> **Status: pending** — [PR #1220](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1220). + +Every stored script is an ordinary command, so you can reach it any of these +ways: + +| Where | How | +|---|---| +| **Projet > Scripts** (*Project > Scripts*) | one entry per script, with its icon | +| the **Scripts** toolbar | one button per script. Hidden while the folder has no script, shown once the first one arrives | +| its keyboard shortcut | `@shortcut`, or one you set in the shortcut settings | +| the **S** shortcut bar | add it with "…" → Customise, like any command (see [Drawing faster](drawing_faster)) | +| command search, **Ctrl+Shift+M** | type the script's name | + +Below the scripts, the **Projet > Scripts** menu holds: + +| Entry | Does | +|---|---| +| *Enregistrer une macro* (*Record a macro*) | see **[Macro recorder](macro_recorder)** (PR #1227) | +| *Gérer les scripts…* (*Manage scripts*) | the script manager, below | +| *Exécuter un script...* (*Run script*) | run any `.js` file once, as before — it moves here from the *Projet* menu | +| *Ouvrir le dossier des scripts* | open the scripts folder | + +### One click, one Ctrl+Z + +> **Status: pending** — [PR #1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219). + +A script run from the editor is **one undo step**, named *Script : <name>*. +A button that adds twenty items is undone with one Ctrl+Z, not twenty. This +also applies to *Exécuter un script…*. A script that changes nothing leaves no +empty step behind. Headless `--run` keeps one step per call, as before. + +### Which sheet the script works on + +> **Status: pending** — [PR #1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219). + +`qet.currentFolio()` returns the index of the sheet on screen, so a button +acts where you are looking. Headless (`--run`, or an assistant testing a copy) +it returns `0`, the first sheet, so the same script can be tried without a +window. It returns `-1` if the project has no sheet. + +--- + +## The script manager + +> **Status: pending** — [PR #1221](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1221). + +**Projet > Scripts > Gérer les scripts…** (*Manage scripts*) lists your +scripts with their icons on the left, and edits the selected one on the right. + +| Field | Header line it writes | +|---|---| +| *Nom :* (*Name*) | `@name` | +| *Icône :* (*Icon*) | `@icon`. Leave it empty for the initials tile, type `builtin:` for a theme icon, or click the preview to choose an SVG or PNG — the file is copied into the scripts folder | +| *Info-bulle :* (*Tooltip*) | `@tooltip` | +| *Raccourci :* (*Shortcut*) | `@shortcut` | +| *Actif :* (*Active*) | `@context`: *Toujours* (*Always*), *Avec une sélection* (*With a selection*), *Avec un conducteur sélectionné* (*With a wire selected*) | + +Below the fields is the script's text, a plain text editor. + +| Button | Does | +|---|---| +| *Nouveau* (*New*) | starts a script called *Nouveau script* from a template | +| *Enregistrer* (*Save*) | writes the file; the button appears or updates | +| *Tester* (*Test*) | saves, then runs it on the current project. Ctrl+Z takes it back | +| *Supprimer* (*Delete*) | asks, then deletes the file, and its icon if no other script uses it | +| *Ouvrir le dossier* | opens the scripts folder | +| *Fermer* (*Close*) | asks whether to save first if the script was changed | + +A script whose header is wrong is listed with the reason (*Pas de bouton : +…*, *No button*), and *Enregistrer* refuses to save a header that would give +no button, with the reason under the editor. + +The manager only writes files. The folder does the rest, so the manager, a +text editor and an AI assistant can never disagree about what a script is. + +--- + +## Letting an AI assistant write the script + +> **Status: pending** — [PR #1224](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1224). + +With the **[MCP server](mcp_server)** set up +(**[Connecting an AI assistant](ai_assistants)**), you can ask: *"make me a +button that puts a Rev A note on the sheet I'm looking at"*. The assistant: + +1. reads the call list with `qet_script_api`, +2. writes the script and tries it with `qet_script_test` — on a **copy** of + one of your projects, which it then compares with the original, so you see + what it would change, +3. stores it with `qet_script_install`, optionally with an SVG icon it drew. + +The button appears in your open QElectroTech. **The assistant never presses +it**: you do. (To let it act on the open project, see +**[live mode](assistant_live_mode)**.) + +| Tool | Does | Needs `QET_ENABLE_SCRIPTING=1` | +|---|---|---| +| `qet_script_api` | every call a script can make, with its arguments, taken from the QElectroTech it targets | yes | +| `qet_script_test` | runs script text on a copy of a project and returns what changed (a `qet_diff`); the project is never modified | yes | +| `qet_script_install` | stores a script as a button: checks the header, writes `.js` and optionally `.svg`. Given `test_project`, it tests first and refuses a script that fails | yes | +| `qet_script_list` | the stored scripts, with their header fields, and the files that give no button and why | no | +| `qet_script_read` | the text and icon of one stored script | no | +| `qet_script_remove` | deletes a stored script, and its icon if no other script uses it | yes | +| `qet_about` | what QElectroTech last wrote about itself: its folders, whether scripting is on, its stored scripts | no | + +`QET_ENABLE_SCRIPTING=1` goes in the environment the MCP server is started in, +as for the editing tools (see [Scripting gate](mcp_server#scripting-gate)). + +**Where the server puts scripts.** The server chooses the folder; a tool call +cannot. In order: `QET_MCP_SCRIPTS_DIR` if set; else the folder QElectroTech +named in `qet-assistant.json`; else the platform folder in the table above. +Set `QET_MCP_SCRIPTS_DIR` if you start QElectroTech with `--data-dir` and it +has not run since. + +### qet-assistant.json + +Whenever an editor window opens, and whenever the stored scripts or the +settings change, QElectroTech writes `qet-assistant.json` in the platform data +folder (`~/.local/share/QElectroTech/QElectroTech/` on Linux, +`%APPDATA%\QElectroTech\QElectroTech\` on Windows) — there even when +`--data-dir` moves everything else, so the server can always find it. It +lists QElectroTech's version, every folder in use (data, settings, scripts, +element and title block collections), whether scripting and live mode are on, +every script call, the stored scripts and the ones refused, and — only while +live mode is open — how to reach it. Only you can read it. `qet_about` shows +it to the assistant, without the live-mode token. + +--- + +## Worked example: a button by hand + +1. **Projet > Scripts > Ouvrir le dossier des scripts**. +2. Save this as `rotate-selected.js` there: + + ```js + // ==QETScript== + // @name Rotate selected half a turn + // @tooltip Rotates every selected symbol on this sheet by 180° + // @context selection + // ==/QETScript== + var f = qet.currentFolio(); + var uuids = qet.selectedElements(f); + for (var i = 0; i < uuids.length; i++) + qet.rotateElement(f, uuids[i], 180); + qet.log("rotated " + uuids.length + " symbol(s)"); + ``` + + With no `@icon`, the button shows a tile with the name's initials. Other calls are + listed on **[JavaScript Scripting](scripting)**, and `qet.apiSignatures()` + returns every call your QElectroTech knows. +3. The **Scripts** toolbar appears with the new button, greyed until you + select something. +4. Select some symbols, click. One Ctrl+Z undoes all the rotations. + +--- + +## Limitations + +- **Your folder only.** No scripts per project or shared across a company yet + (open question 3 in discussion #1226). +- **No questions to the user.** A script cannot yet ask for a value when you + press its button; one button does one thing. +- **macOS has not been tested.** Linux and Windows have, including a Windows + build run under Wine. +- **No arbitrary menu commands from a script**, as before — see + [JavaScript Scripting](scripting#limitations-on-purpose). + +--- + +## See also + +- **[JavaScript Scripting](scripting)** — every call a script can make +- **[Live mode](assistant_live_mode)** — an assistant running scripts in the open project while you watch +- **[Macro recorder](macro_recorder)** — do a task by hand once, and let an assistant turn it into a button +- **[MCP server](mcp_server)** and **[Connecting an AI assistant](ai_assistants)** +- **[Drawing faster](drawing_faster)** — the shortcut bar and command search scripts appear in +- [Discussion #1226](https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/1226) — the proposal diff --git a/scripting.md b/scripting.md index 59c1651..8aabb65 100644 --- a/scripting.md +++ b/scripting.md @@ -52,6 +52,15 @@ qelectrotech --run export_after_revision.js "$1" and runs the chosen script against the *currently open* project. Useful for one-off macros you don't want to wire into CI. +> **Status: pending.** [PR #1220](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1220) +> moves this entry to **Projet → Scripts → Exécuter un script...**, and adds +> stored scripts with their own button, icon and shortcut — see +> **[Script buttons](script_buttons)**. +> [PR #1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219) +> makes a run from the editor **one undo step**, named *Script : <name>*, +> so one Ctrl+Z undoes the whole script; headless `--run` keeps one step per +> call. Neither is merged yet. + --- ## What a script can do @@ -245,6 +254,20 @@ Every method above is either non-blocking by construction, or — for `showMessage` — safe under QET's existing non-interactive mode, which is already on for the whole process before any headless script runs. +### Which sheet is on screen, and what calls exist + +> **Status: pending** — [PR #1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219), not yet merged. + +```js +var f = qet.currentFolio() // index of the sheet on screen; 0 headless; -1 if the project has none +qet.apiSignatures() // every call this build offers, with its arguments +``` + +`currentFolio()` lets a script act where the user is looking, which a +[script button](script_buttons) needs. `apiSignatures()` comes from the +running build itself, so a list made from it (as the MCP server's +`qet_script_api` does) cannot drift from what the build really has. + ### Logging ```js @@ -353,5 +376,8 @@ change of mind shows up in one obvious place: - **[Automating QElectroTech](api_reference)** — the file-format and headless export ground this builds on - **[MCP server](mcp_server)** — an AI assistant driving this engine through `qet_edit`/`qet_query` +- **[Script buttons](script_buttons)** — store a script and run it from a button _(pending, [PR #1220](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1220))_ +- **[Live mode](assistant_live_mode)** — an assistant running scripts in the open project _(pending, [PR #1222](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1222))_ +- **[Macro recorder](macro_recorder)** — record a task by hand for an assistant to script _(pending, [PR #1227](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1227))_ - [PR #891](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/891) — implementation, with the exact tests run against it - [Issue #162](https://github.com/qelectrotech/qelectrotech-source-mirror/issues/162) — the original request and design discussion