104 Commits

Author SHA1 Message Date
ispyisail 8b130497e0 qet-mcp README: print, save/close, changes, live layout check, index cache, standard symbols
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 20:34:26 +13:00
ispyisail 0df8ca5b3c Live mode: print, save/close, changes, snapshot; house-style layout rules; saved symbol index
QElectroTech (LiveServer):
- print: folios to the default (or a named) printer with no print dialog,
  always after asking the user (paper cannot be undone); or to a new PDF
  file. Rendered as the PDF export draws a folio (no grid, no terminals).
- save_project (own file, or save as a new file, never over one) and
  close_project (only without unsaved changes: never discards work).
- changes: the undo history, each step marked assistant or user, with
  "since" to ask what changed after a point.
- snapshot: a copy of the open project as on screen, for a check to read,
  without saving it or changing its file.
- qet.elementTextGeometry(): where a symbol's text is drawn on the folio.

qet MCP server:
- qet_live_print, qet_live_save_project, qet_live_close_project,
  qet_live_changes, qet_live_layout_check (snapshot + qet_layout_check, no
  "run this script?" window); write paths never overwrite.
- Layout rules from the house style, for file and live checks alike:
  label_on_wire, four_way_junction, misaligned_branch.
- The element index is saved under ~/.cache/qet-mcp: a new server process
  loads 8839 symbols in 0.4 s instead of parsing them for 6.9 s; the
  change check is a third faster.
- qet_about lists the installation's standard symbols
  (standard-symbols.json in QElectroTech's data folder) when there are any.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 20:34:14 +13:00
ispyisail 4ceeeed302 qet-mcp README: the live project tools
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 20:34:14 +13:00
ispyisail ad20eb94ba Live mode: open a saved project, switch between open projects
open_project opens a .qet and makes it current, as File > Open does but
with no file dialog and no error windows: a missing, unreadable or
foreign file is refused in the answer. A project already open is only
made current. switch_project makes another open project current, by its
index or its file. status now lists every open project (index, title,
file, folios, unsaved changes, current), so the assistant sees what it
can switch to. MCP: qet_live_open_project, qet_live_switch_project; both
paths go through the workspace policy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:00:13 +13:00
ispyisail 42b1e43e4a Live mode: create a new project (new_project, qet_live_new_project)
An assistant in live mode could only work on the project already open.
new_project makes one as File > New does -- this installation's
new-folio defaults, optional title and number of folios -- and makes it
the current project, so the next request works on it. An optional
absolute path saves it at once, never over an existing file: QElectroTech
refuses, and the MCP server refuses before asking (a new never-overwrite
class in its path policy, so an "overwrite" flag cannot get round it).

Pages and links across pages already worked through scripts
(qet.addFolio, setFolioTitle, linkElements across folios); the tool's
description now says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 18:48:38 +13:00
Laurent Trinques 1c09c4e391 Merge pull request #1282 from arummler/formula-improvements
Auto numeration: a lot of changes for elements, condutors, sheets
2026-10-04 11:52:56 +02:00
ispyisail c49561a76c qet-mcp: better symbol search for NO/NC and schematic symbols (#1178)
qet_element_search matched every word as a substring of the names and
the path, so "NC contact" offered a remanence coil ("nc" in "remanence",
"contact" in its folder) and an outlet before any auxiliary contact,
"normally closed contact" found nothing, and "emergency stop" ranked a
maker's part and two assembly-plan drawings above the push button.

- A word of one or two letters must now be a whole word. Longer words,
  and short ones with a digit, still match inside a word, so German
  compounds ("schutz", "klemme") and "3p" find what they found before;
  on 37 sample queries no result is lost.
- NO, N/O, "normally open", "normalement ouvert" are one word, and NC,
  N/C, NF, "normally closed", "normalement fermé" another.
- Symbols under *_graphics, *_manufacturers_articles and
  *_miscellaneous_unsorted come after every other match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 08:34:29 +13:00
Andre Rummler d76f3528ae AutoNum: a lot of changes
Schemas now get saved with a UUID and do not have to be looked up according to the form. They can be renamed and it gets reflected in existing elements. The GUI for
editing them is now much easier, e.g. forms can be reshuffled. A formula can be applied. Many options now also for conductors and sheets.
2026-10-03 18:09:33 +02:00
ispyisail 173346c712 qet-mcp: qet_check finds crowded terminals and folio reports with several wires
Discussion #1158 asks for a limit on the wires per terminal. Before any
limit, two read-only checks let anyone count their own projects:

- crowded_terminals: terminals with more than four wires (two double
  ferrules, one either side of the screw), folio reports left out;
- reports_with_several_wires: folio report arrows with more than one
  wire, the rule plc-user proposes for reports.

Both are info, not errors: cable, busbar and single-line symbols carry
more wires on purpose, and a third of the shipped examples' reports have
several. Over the 24 examples: 23 crowded terminals in 10 projects
(the worst, 19, is a cable symbol in affuteuse_250h.qet) and 130 reports
in 4 projects. Plain SQL over the conductor table, so they work on any
current QElectroTech.

test_qet_mcp: the checks are read-only, the exact-answer test lists them,
and a coil wired to five others is reported once with its count (checked
to fail with the threshold raised). 398 tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
2026-10-03 22:26:42 +13:00
ispyisail b899d46453 Merge master (#1264, #1265) into feature/qet-mcp-layout-ops
README and tests: both PRs added text at the same places; kept both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
2026-10-03 15:56:00 +13:00
ispyisail d952fb9a0d qet-mcp: place_element takes an angle, for symbols turned along a rung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
2026-10-03 13:41:25 +13:00
ispyisail 372e541a00 qet-mcp: ops that line symbols up so wires come out straight
A wire is straight only when its two terminals are exactly in line, and
qet_edit placed a symbol only by its origin, so an assistant had to guess
where the terminals would land -- and usually missed by a few pixels.

- place_element adds a symbol with one of its terminals in line with
  another symbol's, gap pixels away on the side that terminal faces, and
  notes when the new symbol's terminal faces the wrong way to meet it.
- align_terminal moves a placed symbol across so two terminals line up.
- align_elements lines up symbols' boxes (left/center/right/top/middle/
  bottom), as Edit > Align does.
- distribute_elements spaces symbols' origins evenly, or a pitch apart,
  keeping symbols on the grid on it.

place_element and align_terminal need qet.terminalPosition(); on a build
without it the edit stops before running, naming the missing call, and
every other op still works there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
2026-10-03 13:37:00 +13:00
ispyisail 5f2d31bff7 qet-mcp: add qet_layout_check, a score and fixes for how a drawing reads
A wire is straight only when its two terminals are exactly in line, and a
symbol is placed by its origin with its terminals at an offset from it, so
symbols an assistant places "under each other" by eye land a few pixels
apart and the wire jogs. Nothing told it so.

qet_layout_check reads every symbol and every wire's drawn path through
the scripting API (the default path is not saved in the file) and reports
a 0-100 score with: wires that jog where moving one symbol would make them
straight, extra bends, wires through symbols, overlaps, symbols off the
grid and crossings. "fixes" is one move_element per symbol, planned
together so they can be applied in one qet_edit call: a straight wire pins
its symbols, a move never lands a symbol on another or across a wire, and
symbols lined up with each other go onto the grid together. Styles: iec
(columns), nfpa (rungs) or auto. Read-only.

Over the 23 shipped examples, applying the fixes never lowers a score and
a second check proposes no further moves on 21 of them; a sloppy
assistant-style drawing goes from 40 to 100 in one round, in both styles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
2026-10-03 13:17:09 +13:00
Laurent Trinques e1f14e4b2f Merge pull request #1258 from ispyisail/fix/route-close-symbols
Fix wire routing looping between close symbols (#1178)
2026-10-02 23:15:33 +02:00
Laurent Trinques d8add2b8a0 Merge pull request #1257 from ispyisail/feature/pdf-reproducible
Add repeatable PDF export when SOURCE_DATE_EPOCH is set
2026-10-02 23:15:05 +02:00
Laurent Trinques ff64fdcb00 Merge pull request #1256 from ispyisail/fix/route-review-followups
Fix the follow-ups from the review of wire routing (#1245)
2026-10-02 23:14:51 +02:00
Laurent Trinques 7d61acebd9 Merge pull request #1260 from ispyisail/fix/live-mode-polish
Fix live mode's English text, settings path and screenshot (#1178)
2026-10-02 23:02:54 +02:00
Laurent Trinques 69a71d775f Merge pull request #1254 from ispyisail/fix/settings-dir-macos
Fix #1246: QET_SETTINGS_DIR reads the wrong folder on macOS
2026-10-02 22:58:14 +02:00
ispyisail 5859bc3353 Live mode: English text, the right settings tab, folio-only screenshot
Reported on #1178 after a first try of live mode on macOS:

- The English interface showed the live-mode setting in French. The
  strings were in lang/qet_en.ts but untranslated. This fills in English
  for live mode, the script buttons, the macro recorder and the Connect
  an AI assistant dialog (101 entries); other features' untranslated
  English entries are left for their own change.
- The setting is on Configurer QElectroTech > Général > Projets, but the
  start-up warning, the MCP server's error and its README all said
  "Configurer > Général". All three now name the Projects tab, and the
  README and the server name the English menus and buttons.
- qet_live_screenshot grabbed the whole viewport, so a tall window around
  a landscape folio came back mostly empty. It now crops to the folio's
  frame and title block where they are on screen (the whole viewport if
  the folio is scrolled out of sight), and says so in cropped_to_folio.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 09:14:57 +13:00
ispyisail 84cda1f0b0 Routing: no loops between close symbols, and route inside frames
Reported on #1178: with "route": "avoid", two contacts one above the
other, wired bottom terminal to top terminal 30 px apart or closer, got
a five-segment loop (at 20 px: v 80, h -20, v -140, h 20, v 80) that ran
down through the lower contact and back up past the upper one.

The cause was exitPoint(): it walked out of a terminal until clear of
every obstacle, so with another symbol in front it walked through that
symbol, and the search then had to come back. The same walk made a wire
between two symbols inside a frame (a cabinet drawn as one element)
leave through the frame's side, go round, and cross back in.

The router now knows each terminal's own symbol (Request::start_symbol,
end_symbol; applyRoute() fills them):
- two terminals facing each other on one line with nothing between
  them are joined straight, however close;
- the exit walks through the margin around other symbols but never
  through one; a terminal pointing straight into another symbol gets
  "no-route" instead of a route through it;
- an obstacle drawn around either end's own symbol is left out.
Without the symbols (the old Request), routes are as before.

Rerouting every wire of four shipped examples (perceuse, affuteuse_250h,
Polonez, industrial; 1331 wires): master routes 121 of them through
another symbol, this none (10 pass through a second symbol lying
exactly on an end symbol's rectangle, which no route can avoid). 99
wires that master routed through a symbol now get "no-route" and keep
their path. The 1232 wires both route are 6 % shorter in total
(436,144 -> 410,608 units) with 11 % fewer bends (2256 -> 2010).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 08:43:27 +13:00
ispyisail b0d73080ce Routing: follow up scorpio810's review of #1245
- Rename the `near` lambda in Conductor::setPathPoints() to `isNear`:
  `near` and `far` are empty macros in the Windows headers (minwindef.h).
- Reword the log when setPathPoints() refuses a route. "does not join the
  two terminals" named only one of its reasons; the router always returns
  the two terminals and at least one exit point, so a refusal means the
  route is not a run of horizontal and vertical segments between them.
- README: running along another wire is penalised, not forbidden, so two
  wires can end up drawn on top of each other.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 08:13:31 +13:00
ispyisail 8bbdafe2e4 qet-mcp README: the preset note says frame, not PDF page
The note the op returns reads "...; frame 1223.25 x 791.25 pt"; the README
quoted it as "PDF page".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:51:44 +13:00
ispyisail 51d20abca4 Write the same PDF for the same project when SOURCE_DATE_EPOCH is set
Two exports of one project differed in the creation and modification
dates (the time of the export, in local time) and in the document id
(random). With SOURCE_DATE_EPOCH set (reproducible-builds.org),
--export-pdf now uses the time it names, in UTC, and a document id
derived from the project: version 5 of the project uuid with the
SHA-256 of the project file, so it is the same for the same file and
changes when the file does. Qt has no setter for the dates, so
PdfLinks::setDocumentDate() rewrites them in the document information
and the XMP metadata after the file is written, fixing the XMP /Length
and shifting the xref table. Without the variable nothing changes.

Only --export-pdf reads it; the print window's PDF export does not, as
a person exporting by hand wants the real date.

qet_export (misc/qet-mcp) gains "reproducible" and "source_date_epoch".
It reports whether the build honoured the variable, since an older one
ignores it.

tst_pdfreproducible exports examples/741.qet four times and requires
identical bytes and the epoch's date; it fails with either this change
or the hash seed fix reverted. Projects with cross-reference links also
need their links in a fixed order, which is a separate fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:50:28 +13:00
ispyisail 580cbb1cb1 Merge remote-tracking branch 'upstream/master' into feature/mcp-folio-presets
# Conflicts:
#	misc/qet-mcp/README.md
#	misc/qet-mcp/qet_mcp.py
2026-10-03 07:44:54 +13:00
ispyisail 76cad625af Read QET_SETTINGS_DIR/QElectroTech/ on macOS too (#1246)
On macOS, Qt names the settings subfolder after the organization domain
when one is set, so QElectroTech read <folder>/qelectrotech.org/ while
main.cpp, tst_settingsdir and qet_mcp.py all use <folder>/QElectroTech/.
Clear the domain when QET_SETTINGS_DIR is set, on macOS only. Nothing in
QElectroTech reads it; SingleApplication hashes it into its key, so these
runs no longer hand off to an open QElectroTech.

test_qet_mcp.py: find true on PATH (/usr/bin/true on macOS), and compare
the found binary with samefile() on case-insensitive file systems.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:30:07 +13:00
Laurent Trinques 8fc43aa30f Merge pull request #1245 from ispyisail/feature/mcp-route-around
Add wire routing around symbols to the scripting API and MCP
2026-10-02 14:05:13 +02:00
ispyisail 0b4fc8beb0 qet-mcp: size a folio for a sheet of paper (set_folio_border preset)
setFolioBorder(folio, "preset", "tabloid-landscape") picks the column and
row counts and whole-number sizes that fill the sheet best without going
over it, as one ChangeBorderCommand. The title block and headers are
measured from the folio, so it holds for any template on either edge.
Sizes stay whole because the folio properties panel edits them in whole
pixels. Among fills within 1.5 pt of the sheet, the size nearest the
current one wins: from a new folio tabloid landscape is 23 x 70 by 12 x 82,
not 9 x 179 by 5 x 197. A0-A5, letter, legal, tabloid/ledger, each
-portrait or -landscape; folioPresets() lists them, and folioBorder() reads
"width" and "height" of the frame and title block.

Every preset exports on its sheet; landscape ones rely on the previous
commit, which turns a wide page before matching it to a sheet.

The MCP server checks the name up front, probes for folioPresets(), and
the op's note says what was chosen and the frame's size in points.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 23:00:11 +13:00
ispyisail e345d4e5d0 Give each end of the wiring export its terminal index and uuid
Most shipped symbols leave their terminals unnamed, so --export-wiring
wrote both terminal columns empty and a reader had to work each end out
from the .qet: terminal uuid, then its place in the definition, then the
index. The terminal table now keeps the index the scripting API's
addConductor() takes, from both fills of the database (the document and
the folios give the same value: Element::parseTerminal()'s sort, top to
bottom then left to right), and wiring_list_view and the CSV gain
from/to_terminal_index and from/to_terminal_uuid as their last columns.

The index is left empty for two terminals at one point, where the sort
is not stable and the index is not defined; the uuid tells them apart.
The wiring list dialog reads named columns and is unaffected.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 22:30:49 +13:00
ispyisail 5e28e015e0 Scripting API and MCP: route a conductor around the symbols in its way
A new conductor gets the default two or three straight segments, which
run through whatever symbol or wire lies between its terminals; scripts
then fix it segment by segment with moveConductorSegment().

ConductorRouter finds an orthogonal path on the folio grid that leaves
and enters each terminal in its own direction, keeps clear of every
element's rectangle, stays inside the border, and charges for bends and
for running along or crossing other wires. qet.routeConductor() and
qet.routeConductorBetween() apply it through Conductor::setPathPoints(),
which pushes the same ChangeConductorCommand a handle drag does, so the
path is saved, survives a reload, and one undo restores the default.
Where no route exists the wire keeps its path and the call says so.

qet-mcp: add_conductor takes "route": "avoid", and a route_conductor op
reroutes an existing conductor (by terminal or by uuid). The router
methods are required only by an edit that routes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 22:28:11 +13:00
ispyisail 51b1229935 Merge pull request #1228 from ispyisail/feature/mcp-macro-recorder
Add MCP tools to read macro recordings and check scripts against them
2026-10-02 15:14:16 +13:00
ispyisail f6867a0f4e Merge pull request #1225 from ispyisail/feature/mcp-live-tools
Add MCP live tools to act on the project open in QElectroTech
2026-10-02 15:13:29 +13:00
ispyisail 0f909e1246 Merge pull request #1224 from ispyisail/feature/mcp-script-tools
Add MCP tools to write, test and store script buttons
2026-10-02 15:13:08 +13:00
ispyisail f4660f19ec qet-mcp: macro recordings -- read what a person did, check a script against it
qet_recording_list and qet_recording_read fetch what QElectroTech's macro
recorder saved: each step from the undo history as structured changes
(consecutive folio states diffed with qet_diff), and the overall change
from before.qet to after.qet. qet_recording_check runs a script on a copy
of before.qet from where the person started -- the folio on screen (a
proxy answers qet.currentFolio(), which a Qt object will not let a script
replace) and the selection -- and says whether the result matches
after.qet, or what differs. qet_recording_remove deletes one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 14:06:51 +13:00
ispyisail a99c58487d qet-mcp: find the live channel in qet-assistant.json
QElectroTech now advertises its live channel in the "live" part of
qet-assistant.json instead of a live-session.json of its own. When nothing
is listening, the error now tells apart QElectroTech not running, live
mode switched off, and the start-up warning not accepted.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 13:03:33 +13:00
ispyisail 15c114edd5 qet-mcp: read qet-assistant.json; qet_about; a note at first contact
QElectroTech now writes qet-assistant.json with its folders, features,
script calls and stored scripts. The server reads it to find the scripts
folder -- right even when QElectroTech runs with --data-dir, where the
per-platform guess was wrong -- and qet_about shows it, never the live
token. The initialize reply now carries instructions: what QElectroTech
is, headless and live, the usual order of tools, start with qet_about.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 13:02:26 +13:00
ispyisail ae06377f1a qet-mcp: live commands, folios, undo of the assistant's own step, screenshot
qet_live_screenshot returns an MCP image the assistant can look at;
--call prints an image part as a data: URI instead of failing on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:40:29 +13:00
ispyisail bf74468c40 qet-mcp: live mode tools, to act on the project open in QElectroTech
qet_live_status, qet_live_run_script and qet_live_run_stored talk to a
running QElectroTech through the channel its LiveServer opens, only when
live mode is switched on in its settings and accepted at this start. They
find it through live-session.json in QElectroTech's data folder and send
its token on every request; with no session, the error says which of the
three switches is missing. Running needs QET_ENABLE_SCRIPTING=1 as editing
does; asking for the status does not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:27:25 +13:00
ispyisail cd51f39d7b qet-mcp: the scripts folder rule as a pure function, tested for Windows and macOS
Checked against a real Windows package under Wine: QElectroTech keeps its
data in %APPDATA%\QElectroTech\QElectroTech, next to which the scripts
folder goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:05:24 +13:00
ispyisail 55eac848df qet-mcp: tools to write, test and store scripts that QElectroTech shows as buttons
qet_script_api lists every qet.* call, asked of the QElectroTech that will
run it (qet.apiSignatures() where the build has it, names otherwise), with
the header format that makes a script a button.

qet_script_test runs a script's text on a copy of a project and returns the
qet_diff of what it changed, its log and its errors with their line.

qet_script_install stores a script, and optionally an SVG icon, in the
scripts folder QElectroTech reads; with test_project it tests first and
stores nothing if the test fails. qet_script_list, qet_script_read and
qet_script_remove complete the set.

The folder is the server's choice, never the call's: ids are checked as
file names, and storing or removing needs QET_ENABLE_SCRIPTING=1 like an
edit, because a stored script runs when the user clicks it. A header is
checked with the same rules as QElectroTech's own, so nothing is stored
that would get no button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:13:05 +13:00
ispyisail 7df9052a47 qet-mcp: set a folio's conductor defaults (set_conductor_default)
The "one text per potential" switch (onetextperfolio) lives in a folio's
conductor defaults, which no scripting call or qet_edit op could reach, so
callers patched the saved .qet afterwards (#1178).

qet.setConductorDefault(folio, property, value) sets onetextperfolio or any
setConductorProperty name on a folio's defaults, or with folio -1 on the
project's defaults that new folios copy. A change to onetextperfolio
re-shows or hides the conductor texts at once, as the Folio properties
dialog does. Not on the undo stack, like both dialogs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 07:16:44 +13:00
ispyisail 65a1080cd3 Keep headless runs' settings in a folder of their own (QET_SETTINGS_DIR)
The MCP server gives each QElectroTech run a private HOME and writes the
element collection path for it (elements_dir) into
~/.config/QElectroTech/QElectroTech.conf there. Only Linux reads that
file: Qt keeps settings in the registry on Windows and in the system
preferences on macOS. So on those systems elements_dir did nothing, and
every run read the user's own settings (#1178).

When QET_SETTINGS_DIR names a folder, QElectroTech now keeps its
settings in <folder>/QElectroTech/QElectroTech.ini on every system. It is
set in main() before the first setting is read. Without the variable
nothing changes.

The server sets it for each run and writes the collection path to the
.ini as well as the .conf, so an older QElectroTech keeps working on
Linux. The path is written with forward slashes: Qt reads a backslash in
these files as an escape. The README notes that elements_dir needs this
on Windows and macOS, and that long arguments go on stdin with "-"
(Windows refuses a command line over 32,767 characters).

tst_settingsdir: a script places a symbol that only the folder's settings
can resolve, while the usual settings file points at an empty collection.
It fails on master and passes here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:00:55 +13:00
ispyisail fd7aec4071 Merge pull request #1137 from ispyisail/feature/qet-mcp-windows-python
Offer Python with the Windows installer, for the MCP server
2026-09-29 18:53:01 +13:00
ispyisail 2511566d8b Merge pull request #1136 from ispyisail/feature/qet-mcp-install
Install the MCP server with QElectroTech
2026-09-29 18:52:36 +13:00
ispyisail 9778dc0a86 Merge branch 'feature/qet-mcp-install' into feature/qet-mcp-windows-python 2026-09-29 14:37:53 +13:00
ispyisail c4b1e02810 Merge remote-tracking branch 'upstream/master' into feature/qet-mcp-install 2026-09-29 14:37:43 +13:00
ispyisail 7fa2643ac5 Merge remote-tracking branch 'upstream/master' into fix/qet-mcp-windows-launch
# Conflicts:
#	misc/qet-mcp/test_qet_mcp.py
2026-09-29 14:37:36 +13:00
ispyisail 06fc5153c1 qet-mcp: make QElectroTech launches work on Windows
On Windows every tool that starts QElectroTech (qet_export, qet_edit,
qet_query, qet_check, qet_continuity, qet_project_new) failed, for two
reasons:

- The server ran a copy of the executable from a temporary folder, to get
  its own SingleApplication key. A Windows program loads its DLLs from its
  own folder, so the copy died before main() with 0xC0000135 (DLL not
  found). Every flag the server passes is a CLI export flag or --run, and
  main.cpp handles both before it constructs SingleApplication, so on
  Windows the original is now run. The copy stays elsewhere.
- It set QT_QPA_PLATFORM=offscreen. The Windows packages ship only the
  qwindows platform plugin, so Qt found none and stopped at a message box
  nobody could close: every call hung until its timeout. Windows now keeps
  its default platform; the export flags and --run open no window.

Checked under Wine (qet-wine-smoke) on the fork's CI Windows build, run
through python.org's embeddable Python: before, qet_export ended with
exit 3221225781; after, a PDF export, a qet_query (98 elements, as on
Linux) and a qet_edit placing a common:// element all succeed. The hang
was isolated by launching the same export from bash (works) and from
Python with one change at a time: only dropping QT_QPA_PLATFORM made it
work. Four unit tests pin both choices per platform; each fails with its
fix removed. Suite 262/262 none skipped on Linux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 14:25:06 +13:00
ispyisail d0a439a448 Merge pull request #1133 from ispyisail/test/qet-mcp-audit-element-tools
Add exact-answer tests for qet_check, qet_continuity and the symbol-file tools
2026-09-29 14:23:13 +13:00
ispyisail 0392d74e15 Merge pull request #1131 from ispyisail/fix/qet-mcp-folio-ref-uuid
Fix qet_edit's folio "$id" naming the wrong folio after an insert
2026-09-29 14:22:54 +13:00
ispyisail 37eb7ce5ac Merge pull request #1130 from ispyisail/test/qet-mcp-audit-survivors
Add qet-mcp tests for what a second mutation audit found untested
2026-09-29 14:22:35 +13:00