mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-06 20:02:16 +00:00
release
311 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fbd30b0bd0 |
Panels: inspect and change layouts through commands (#11304) (#11454)
* claim: #11218 * Panels: add shared layout rules and retained content runtime * claim: #11304 * Panels: inspect and change layouts through shared commands (#11304) * Panels: account for layout commands in geometry coverage |
||
|
|
603c974f37 |
Fix main's build: the CLI imports the B-rep type from its new home (#11634)
The CLI's kernel_cases_export.rs still imported Brep from solidcraft_geom::brep after the layer split moved it to solidcore_record::brep. Changes this one import. |
||
|
|
dc38349cbf |
Layer split stage 1: the B-rep record, native body file and Vec/Plane come from solidcore-record (#11496)
* Kernel: the B-rep record and the native body file come from solidcore-record SolidCraft's portable B-rep record (`solidcraft_geom::brep`: brep.rs, topology, history, envelope, part, curve2) and the native body file (`solidcraft_kernel::native`: the tagged binary codec and the container) move to solidcore's `solidcore-record` crate: geometry as data, with structural validation and no maths (solidcore's docs/layers.md, stage 1). Every caller uses `solidcore_record::brep` and `solidcore_record::native`; the old copies are deleted. What computes from coordinates stays with the kernel, in geom's `brep`: - `brep::check`: the record's geometric checks (orthonormal frames, non-degenerate planes, unit revolution axes, non-singular placements). `check::validate` and `check::validate_built` are the record's validation and these together, and every caller of `Brep::validate` uses them, so what is accepted is unchanged; - `brep::label`: a surface's natural ranges (a cone's apex), `curve_interval`, `edge_curve_interval` and `form_turns`; - `brep::pcurve::eval`: a pcurve's point; - `geometry::check`, `placement::moved` and `split_edges` become functions on the record. The kernel's native module keeps the conversion between a body and its saved record (metadata.rs) and checks the decoded record's geometry. `native/analytic.rs`, which no module declared, is deleted. solidcore-record is pinned to its rev on solidcore's `layer-record` branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NvoxKMbMFSQU8tzRtoJhtT * Geometry: Vec2, Vec3, Plane and the profile types come from solidcore-record The plain data of vectors and points, sketch planes and planar profiles (`Seg2`, `Loop2`, `Region2`) moves to `solidcore-record`, with its constants and component-wise operators only (owner decision, solidcore layer split). Their geometry stays in geom as traits: `Vec2Geom`, `Vec3Geom`, `PlaneGeom`, `Seg2Geom`, `Loop2Geom`, `Region2Geom`, `Seg2ArcFit`, `Loop2ArcFit` and `Region2ArcFit`, in scope with `use solidcraft_geom::prelude::*`. Every caller names the types from `solidcore_record`; geom no longer defines or re-exports them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NvoxKMbMFSQU8tzRtoJhtT * Kernel: pin solidcore-record to solidcore main f5e8e9a29 solidcore-record is merged on solidcore main (tangency-labs/solidcore#2519); its crate there is identical to the rev pinned before but for its clippy configuration. The lock is regenerated against the merged rev. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NvoxKMbMFSQU8tzRtoJhtT --------- Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1b51a0678b |
Merge pull request #11568 from tangency-labs/jyviko/rig-export
Kernel rig: export each case's kernel operations as a corpus for solidcore's rig |
||
|
|
e438a9bbea |
Web app: choose the release, the release candidate or the edge build (#11419)
The web app is now offered at /app/ (latest release), /app-rc/ (newest release candidate) and /app-edge/ (current main), each with its own browser storage. /app/ is built from the latest release's web zip instead of main. |
||
|
|
7b0906b918 |
Kernel rig export: review fixes
- Picks run on a copy of the operand: a pick builds query caches on the body it reads, so the traced body stays as an untraced run leaves it. - An untrim and an extension record their picks with the pickers they run (`face_at`, `nearest_edge`). - A final body matches the newest export of its record that an operation made. - A stopped run is the kernel's when the last failed operation is followed by copies only. - A re-export removes each case's old entry first; fixes.json is written whole. - The manifest names no commit for a copy without git, never an empty one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DtL5M41G8Nua7HvuFPZkmJ |
||
|
|
5fd0ac98a9 |
Kernel rig export: a failure is the kernel's when the last traced operation failed; grades SolidCraft computes are listed apart
An entry's operation is expressible when the kernel accounts for its result; the values only SolidCraft grades (continuity, meshes, files, command answers, merged counts, SolidCraft's wording of a refusal) are listed under `ungraded` instead of making the whole case inexpressible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DtL5M41G8Nua7HvuFPZkmJ |
||
|
|
9c65a30265 |
Kernel rig: export each case's kernel operations as a corpus for solidcore's rig
`cargo xtask kernel-cases [--ladder] --export DIR` runs the rig with the kernel's operations traced (`smlib::trace`) and writes one entry per case: the operation, or chain of operations, that made the bodies the case ends with; each operand that came in as a record, as that record; the parameters, with every pick by points also given as the topology index it picked; the fix set; the case's expected values and the rig's result. A case no kernel operation alone accounts for is written too, marked not expressible with its reasons. DIR/manifest.json counts them per area. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DtL5M41G8Nua7HvuFPZkmJ |
||
|
|
c5ccb9201d |
Wave 43/45: smlib: rustfmt after the C++ kernel's removal (and 1 more)
2 commits, squashed; the originals stay reachable from branch jyviko/merge-main-develop-solidcore (#11360). - |
||
|
|
28e983e191 |
Wave 39/45: diagnostics.kernel takes a typed contract, as main's other diagnostics commands do
1 commits, squashed; the originals stay reachable from branch jyviko/merge-main-develop-solidcore (#11360).
-
|
||
|
|
ea772a0438 |
Merge develop into main: SolidCraft on the SMLib kernel (v1.1.0-alpha) (#11351)
* UI: rim and wall picking tests for a circle of arcs that is one wall A circle drawn as two half arcs now extrudes to one full-turn wall with its seam edge, and each rim is one closed edge (tangency-labs/smlib#67). The tests keep their intent on that body: a rim clicked once is one item, measured and highlighted whole and picked from either side; a wall picked either side of its seam is the same surface, lit whole, and toggles off from the other side; every face is its own patch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fillets: a later round at a corner where earlier rounds meet blends them again with it The owner's ruling of 2026-10-30: a later fillet on an edge at a vertex where earlier rounds already meet in a mitre makes the corner rounding all of them at once makes, one smooth patch, the mitre gone. A body made by constant-radius rounds keeps what they were made on and which edges they rounded at which radius; a later round reaching such a corner blends the earlier rounds' edges (from the earliest of those meeting there on) with the new edges in one SMLib blend of the body before them. The result's history is put over the body the later round was given: an earlier round's face is that face trimmed anew (its name kept), the corner patch and the new rounds are the later fillet's. A picked mitre seam has no round of its own: it is refused unless a new edge of its radius meets it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: a later r3 round at an r2 mitre, through the Fillet feature, makes the all-at-once corner Two box edges rounded r2 in one fillet, then the upright edge at their mitre r3 in a second fillet (tangent chain on, so the seam comes with it): 10 faces, 7928.743041 mm³ as fillet_radii of the box gives, the r2 rounds' names kept, the r3 round and the corner patch the second fillet's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Kernel: a body's record of rounds goes with its history, and can be read back The rounds that made a body are over the body its history is over: a new history (an operation carrying a step's result back to its own operands) leaves the record out, so a later round never reads one history against another body. Body::rounds gives the record and Body::with_rounds_of takes one back, checked (edges of the body before them, a fillet's radii, the body's history over that body), for a saved model to keep it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Model cache: a body made by rounds keeps them, so a later round blends them the same after opening A design gave another body when opened from its model cache: the rounds a body was made of lived only in memory, so a later round at their mitre was built sequentially (or refused, as too large) after opening and blended with them when evaluated anew. The saved model now records, per kernel body made by rounds, the body they were made on (a place in the bodies, stored once though no state holds it) and the edges with their radii; reading it attaches them back down each chain, and a thinned model keeps those bodies with the bodies made from them. Model cache format 7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: a corner patch of rounds 2/3/4 takes no more than the strips leave in its block three_rounds_at_a_corner bounded the patch's extra cut at 3 mm³ beyond the strips, a figure with no derivation; SMLib's all-at-once body at radii 2, 3, 4 takes 3.099 (V 7878.579574 against strips 7881.678). That body is the strips' outside the block its patch lies in: its rounds are the strips' cylinders ending at a's section y = rc, b's x = 20 − rc and c's rails where they meet a's and b's (the patch's four corners, now asserted), so the patch takes at most what the strips leave in that block (11.86 at 2/2/3, 32.69 at 2/3/4). The lower bound is that block; the upper one, at most the strips' volume, stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: the io crate's hand-built saved models list their rounds, as format 7 records do Model cache format 7 ( |
||
|
|
c4808e4715 |
MCP: clean up empty scratch folders on shutdown (#7836) (#7929)
* claim: #7836 * fix(mcp): remove empty scratch directories on command exit |
||
|
|
21fc384e40 |
Control channel: a new connection has five seconds to show its token (#10961)
A client could connect and send nothing, or only blank lines, and hold one of the 16 connection seats for as long as it liked. All reads before the token now share one five-second deadline; the connection is then closed without a reply. An authenticated connection may idle as before. `solidcraft-cli mcp --connect` used to open a connection at start and hold it until the first tool call. It now only checks that the app is there, and the first call connects. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
425417b36a |
Web app: open a large design without freezing the page, with progress and Cancel (#10198) (#10211)
* Engine: open a design a feature at a time (#10198) OpenSteps splits doc.open of a design into steps for a caller that must keep working meanwhile (the web app, which has one thread): start reads the file, each step evaluates the next feature by moving a copy's history marker one feature on (so every result before it is reused), and finish puts the design in the session's place with doc.open's reply. The next feature's imported STEP text is offered first, so a caller can read it in parts. Session::opened and opened_at are split into small helpers so both paths build the session the same way; doc.open is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Web app: open a design a few features a frame, with progress and Cancel (#10198) On the web, a design to open is now a staged file load like a STEP file (#1376): its features are evaluated for about 30 ms a frame through OpenSteps, a feature's imported STEP file is read a solid per frame first and held so the feature finds it read, the progress card counts the design's features, Cancel works between steps, and the meshes are made a few per frame afterwards. The desktop app keeps its worker thread. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Web app: design links and the files window open designs with progress and Cancel (#10198) Design links (?open=URL, as embedded viewers use), the files window and designs opened from the computer went through the one-shot open_path, which froze the page on a large design. They now use the staged open; a design link becomes an unsaved copy under the link's name once the open's reply arrives (SolveApp::open_path_answered). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
bba2fc1400 |
Report omitted print-face selections in command-script exports (#10230) (#10235)
* claim: #10230 * fix: report omitted print-face assignments in script exports |
||
|
|
538d7fcb43 |
Language: follow the system language by default (#10138) (#10183)
* claim: #10138 * Follow the system language on a first start (#10138) The language preference defaults to a new 'system' value: the OS locale (sys-locale) is matched against the catalog list - exact tag, base language, then English - and a System choice sits at the top of the Preferences language list. A saved language still wins. * Drop the explicit deref clippy flagged; regenerate THIRD-PARTY-LICENSES.txt for sys-locale --------- Co-authored-by: Dahak Builds <dahakbuilds@users.noreply.github.com> |
||
|
|
34c378c063 |
Save As: rename the design to the new file's name (#4907) (#10036)
* claim: #4907 * Save As: rename the design to the new file's name when its name was borrowed (#4907) --------- Co-authored-by: Dahak Builds <dahakbuilds@users.noreply.github.com> |
||
|
|
1bcc1125f0 |
Graphics: apply the chosen card, or say when it could not (#8341) (#9252)
* claim: #8341 Co-authored-by: Cursor <cursoragent@cursor.com> * Graphics: keep a preferred card when surface marks it incompatible (#8341) Prefer the saved adapter by exact then case-insensitive name, including when only listed as surface-incompatible, and explain in Preferences when another card is still in use. Co-authored-by: Cursor <cursoragent@cursor.com> * Format and clippy Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2f6ca7e46b |
Linux: optional system title bar (server-side decorations) (#9263)
On Linux the window always had no OS decorations and drew Windows-style caption buttons in the application bar. SOLIDCRAFT_TITLEBAR=system, or "titlebar": "system" in graphics.json, now opens the window with the desktop's own title bar and buttons (server-side decorations where the compositor offers them). The default is unchanged; Windows and macOS are unaffected. Claude-Session: https://claude.ai/code/session_01Gnm1n2PVPqghMuR9kHWXfh Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
b8eb8d262c |
Settings: saved to disk as soon as they change, not only when the app closes normally (#8275) (#9711)
* claim: #8275 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Settings: written to disk in the frame they change, not only at a clean exit (#8275) eframe saves app.ron every 30 s and when the window closes normally. A change made since the last save was lost whenever the app didn't close normally: ended from the Task Manager, stopped by a sign-out or shutdown, or crashed or hung in the graphics driver on the way out. The next start then showed the old settings (View navigator back to Axes, Display quality back to Normal). The desktop app now writes its settings and flushes them in the frame they change (frames with input and the one after), as the web app already does (#8644). Unchanged settings are not written again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Settings: write at most once a second, and only after input that can change them (#8275) Review: pointer motion came in every frame while the mouse moved, so the settings were serialized every frame; and some settings change in every frame (a panel's width while its edge is dragged), which would have flushed app.ron on the UI thread each frame. Only clicks, keys, text, paste, wheel and pinch count as input now, and the file is written at most once per second: a change made in between waits, a repaint is asked for when its second is over, and it is written then, so an idle app still writes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
edcf02c0d4 |
Crash reports: a window opened after startup no longer labels the run 'during startup' (#8776) (#9661)
* claim: #8776 * Crash reports: a window opened after startup no longer labels the run "during startup" (#8776) egui-wgpu reports "window surface" and "surface configure" for every native window, also the ones opened after startup, such as the agent chat in its own window. Each one overwrote the journal's "running" phase, so a later unclean exit was reported as "during startup (surface configure, N s after launch)". crash::startup_step records a startup step only until the app runs, and the app's egui-wgpu hook calls it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
fc499441e2 |
Lost GPU: the old process exits instead of hanging in the driver, after the settings are saved (#9044) (#9054)
After a lost device the next start began from on_exit, while eframe was still writing app.ron, and the old process then hung in vkDestroySwapchainKHR on NVIDIA. Start it from Drop for App instead, after eframe has joined the settings save and before it drops the window's GPU surface, and end the process there after a loss. The update restart moves there too. The loss reason is passed to the next start and shown in its note. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
32900556e0 |
Control server: a subscribed connection is told of design changes (#8315) (#8333)
* claim: #8315 * fix(control-server): release the watch seat deterministically (#8315) The seat a subscribed connection holds on the DesignWatch lived in the events thread alone, so it left the watch only when that thread ended: on the first write a closed client refuses, which needs the design to move, or when the thread noticed the end of the stream, which waits for the connection's own thread to come out of its blocking read. A closed connection could therefore keep counting on the watch for a second or more, and the test that asks for the count to be gone could lose its race with the ten seconds it waits. The seat is now shared: it leaves the watch once, whichever thread sees the connection's end first, the connection's own thread at the end of the stream or the events thread at the first refused write. The count of subscribed connections is right as soon as the connection is gone, and the events a subscribed connection is told of do not change. |
||
|
|
6c9afc6f7e |
Start the window on OCLP Macs with SYSTEM_VERSION_COMPAT=1 (#3080) (#8930)
On Macs patched with OpenCore Legacy Patcher the OS reports a newer macOS version than the GPU's Metal compiler supports, so wgpu picks a shader standard the compiler refuses (`invalid value 'metal3.2'`) and the window never draws. The variable has to be set before the process starts, and Rust 2024 makes `set_var` unsafe (this crate denies unsafe code), so main() now re-launches the binary with SYSTEM_VERSION_COMPAT=1 when the OCLP NVRAM key (OCLP-Version) is present, and exits with the child's status. A process that already has the variable set never re-launches, so there is no loop and a user's own value is respected. If the check or the spawn fails, startup continues normally. Tested on an OCLP Mac: one re-launch message, graphics render correctly; with SYSTEM_VERSION_COMPAT=1 set beforehand it does not re-launch. Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> |
||
|
|
aff8106205 |
Help: check for updates and show results in the selected language (#8896)
* Help: add manual update checks and status window * Test manual update checks and localized results * Add update check to the native Help menu * Localize Help update checks in all app languages * Document manual update checks from Help * Document ui.help updates control action |
||
|
|
21340ba019 |
Web: Chinese UI loads a Chinese font (#8894) (#8981)
* claim: #8894 Co-authored-by: Cursor <cursoragent@cursor.com> * Web: load Simplified/Traditional Chinese fonts for zh and zh-TW (#8894) BIZ UDPGothic only covers Japanese, so Chinese UI showed tofu. Ship locale-glyph Craft UI SC/TC subsets and fetch the matching face on demand. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
6e39efd4ac |
Theme: System follows the desktop's dark/light setting on Linux GNOME (#7944) (#8123)
* claim: #7944 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Theme: System follows the desktop's dark/light setting on Linux (#7944) On GNOME (Wayland, or X11 through XWayland) the window toolkit never reports the desktop's dark or light preference, nor its changes, so Theme: System kept its colours. The Linux app now reads org.freedesktop.appearance color-scheme through the XDG Desktop Portal's Settings interface (then GNOME's color-scheme and gtk-theme when it has no preference) on a thread of its own, follows the portal's SettingChanged signal, and falls back to gsettings or a slow poll. The window reads the answer through Services::desktop_dark; the decision from the raw values is prefs::desktop_prefers_dark. Windows and macOS keep the window toolkit's theme. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
63923da2ca |
Viewport: an opened design is framed at the home view, in the middle of the view (#9195) (#9204)
* claim: #9195 * Viewport: an opened design is framed at the home view, in the middle of the view (#9195) A fit the viewport cannot frame yet is kept and asked again on the next frame instead of being consumed and lost, so a design opened from the Home screen or by launching on a file no longer comes up at the default camera, wherever its own coordinates put it. Framing then centres the model on the view rather than on the free rectangle between the floating controls: `Layout` carries `middle`, the view without the panels, computed before the compass, the navigation bar and the OK/Cancel corner join the obstacles. The model is still sized to `drawable`, so it stays clear of every control, but only a panel moves it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Viewport: keep the centred fit clear of the controls, and frame --sample (#9195) The fit framed the model into a rectangle the size of `drawable` centred on `middle`, which is not inside `drawable`, so the model could sit under the compass, the navigation bar or the render product frame. The model is now sized to `drawable` as before, and only the room left over in it moves the model towards the middle of the view. `s27_move_triad` turns the Z ring on its far side: the model now sits further right, and the Move dialog that docks on the right afterwards covered the ring's old grab point. A launch with `--sample` builds the design straight into the session and never asked for a fit; it now comes up at the home view, framed, like an opened design. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Viewport tests: the cursor orbit's pivot keeps the pixel it was picked on (#9195) With the model now centred on the view, one of the test's perspective drag points lands within the pick tolerance of the box's top edge, and the pick snaps the pivot onto that edge, a few pixels from the cursor. The orbit keeps that point still, as it should; the test compared it with the cursor instead of with where it started. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
92af4a21c8 |
Control channel: a per-request param_check level, applied and confirmed by the app (#9184) (#9185)
* claim: #9184 * Control channel: a request's own param_check level, applied and confirmed by the app (#9184) `engine.execute`, `engine.batch` and `engine.script` take an optional `param_check: "off"|"warn"|"strict"` in their params. The app runs the request at that level through the same `run_checked` path and batch preflight a headless session uses, puts its own level back, and every reply says the level it ran at as `param_check` beside `ok`. A command that switches designs keeps the app's level; any other word is refused. Readings and exports answered on a copy off the window thread keep the level too. `control.capabilities`, answered at once on the control-server thread, lists what the channel does beyond the methods every version has: `{"param_check": ["off", "warn", "strict"]}`. An older app answers "unknown method". The MCP bridge asks it once per connection. When the app lists the level, every call and batch goes with it and the app checks against its own commands; otherwise the bridge checks before sending, as #9073 does. At strict, a reply that doesn't say the app checked the call is an error, and the next calls are checked by the bridge. Also: `add_param_warnings` takes the reply by `&mut`, and `with_param_check` sits beside `Remote::new`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Control channel: a design-switching command is checked at the request's level Review fixes for #9184. `component.edit_in_place`, `component.finish_edit`, `view.next_tab` and `view.previous_tab` ran at the app's own level and echoed `off`, so a misspelt call went through at strict. They now have their parameters checked at the request's level before they run (and still run at the app's own level, as each design keeps its own), and the reply echoes the requested level. The MCP bridge at strict now requires the echo to match its level, not just to be there. `param_check` is read only by `engine.execute`, `engine.batch` and `engine.script`; other methods ignore it. The off-thread test now shows the design change computing off the window thread before it is refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4a781b8cd8 |
MCP: --param-check checks calls to the running app (#9072) (#9073)
* claim: #9072 * MCP: --param-check checks calls to the running app (#9072) `mcp --connect` (and `mcp` once it bridges to an app) took `--param-check` and forwarded every call unchecked, while the app's own session is always off. `Remote` now checks each `engine.execute` and `engine.batch` against this server's command contracts before sending: `strict` refuses a call, or a batch with such a step, without sending anything, and `warn` adds `param_warnings` to the app's reply (each step's result in a batch). A command with no contract here goes to the app unchecked. `Auto` carries the headless session's level over when it bridges to a late app. `batch_preflight::contracts` is the contract half of the existing preflight, for a runner in another process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2356a63aea |
CLI: run takes --param-check (#6921) (#6924)
* claim: #6921 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CLI: run refuses unknown options and takes --param-check (#6921) `solidcraft-cli run` now checks its options through `known_args`, so a mistyped option fails instead of being ignored, and takes `--param-check off|warn|strict` with the MCP server's words and default `off`. `warn` prints each unknown key with a suggestion on stderr and runs the step; `strict` stops at that step and writes nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * CLI: run's option check takes --param-check; warn on timed runs as steps complete `run` keeps #6919's (#6918) unknown-option check, with `--param-check` among the options that take a value. `Session::run_script_timed` now takes the same per-step callback as `run_script_each`, so `run --timings` or `--profile` at the warn level reports a step's warnings even when a later step fails, instead of after the script (and not at all on a failure). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9b97e06f71 |
Web: open tabs share settings changes, so one tab no longer undoes another's (#8644) (#8832)
* claim: #8644 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Web: open tabs share settings changes, so one tab no longer undoes another's (#8644) Every open tab of the web app saved its whole copy of the settings to the same browser storage, every 30 s and on focus loss, so a tab still holding old settings put them back over a toolbar change made in another tab. A tab now writes its settings in the frame they change, and the other open tabs load them from the browser's storage event, so their own saves keep them. Settings loaded that way aren't written back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
5f11d92458 |
Opening a design pins its body names, so the first undo evaluates nothing (#8939)
Problem: a design saved before body names were pinned (#6403) is pinned by its first command that changes it, as part of that command. Undoing that command went back to the unpinned design, whose fingerprints no evaluated result matched any more, so the first undo after opening evaluated the whole timeline again: 63-72 s in the SELENE rover (5,484 features) when opened from the command line or headless (`Session::opened_at`), 0.08 s with this change. `doc.open` pinned at the end of the command instead, which kept undo fast but left the design with unsaved changes on opening. Solution: `Session::opened_at` pins the names as it opens the design, with the names the file's bodies have (no result changes, so nothing is evaluated), and takes the pinned design as the saved one: opening is no change. Claude-Session: https://claude.ai/code/session_013WUFq6QFBqmZjxwaKy2J1M Co-authored-by: Markus Kaltenbrunner <kaltenbrunnermarkus@users.noreply.github.com> |
||
|
|
3e01081ff9 |
Control token: a closing window removes only its own token and discovery files (#8794) (#8837)
* claim: #8794 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019FAWPuFoh9qxn2uS2j53QZ * Control token: a closing window removes only its own token and discovery files (#8794) Under Flatpak each instance has its own loopback, so a second window binds the same port number as the first and writes the same <port>.token, <port>.pid and current.port in the shared data folder. At exit the first window deleted them all, unconditionally, leaving the second window running with no token file a client could read. remove_token_file now takes this launch's token and removes the token and process files only while the file still holds it; the process id can't tell instances apart, as every Flatpak instance has the same one. remove_current_port also takes the token and keeps the discovery file while another launch's token file holds that port, and removes current.pid with current.port (it was left behind). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019FAWPuFoh9qxn2uS2j53QZ --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
cb05e1e0f7 |
GPU path tracer: run on Metal on macOS (#7183) (#7185)
* claim: #7183 * GPU path tracer runs on Metal on macOS, not only Vulkan (#3217) |
||
|
|
0baf49b25f |
Windows: never load a dxcompiler.dll found on PATH; FXC unless DXC ships beside the app (#6756) (#7923)
* claim: #6756 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Windows: never load a dxcompiler.dll found on PATH; FXC unless DXC ships beside the app (#6756) wgpu's Dx12Compiler::Auto loads dxcompiler.dll by name, so Windows takes the first one on PATH. SolidCraft ships none, and DXC 1.8.2505 from other programs' folders (Obsidian, NVIDIA SDK Manager) crashed every start with EXCEPTION_ILLEGAL_INSTRUCTION during the viewport shader compile. solidcraft_gpu::dx12_compiler() now chooses: WGPU_DX12_COMPILER as wgpu reads it when it names a compiler; otherwise DXC from the dxcompiler.dll beside the program, by its full path, else FXC. The window, the headless/CLI instance and the test helpers start with it, and dx12_compiles_with_fxc follows it. WGPU_DX12_COMPILER=dxc keeps the old lookup. Fixes #6756 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4571701179 |
Embed a Windows version resource in solidcraft.exe (#8378)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e6dc105134 |
Point clouds: insert PLY, XYZ and PTS scans as a modelling reference (#5151) (#5381)
* Point clouds: insert PLY, XYZ and PTS scans as a modelling reference (#5151) A point cloud is kept in the design as a reference, drawn as depth-tested dots and never a body. - io: a PLY reader (ASCII, binary little/big endian; x, y, z of any numeric type, optional colours, other elements skipped; counts checked against the file) and XYZ/PTS text, thinned evenly past max_points. PLY meshes with faces can also come in through file.insert_mesh. - doc: Document.point_clouds (shared f32 points relative to an f64 origin, colours, units, rigid placement, size and colour), stored as a binary container part; format change in pending/point-clouds.rs. - engine: pointcloud.insert / edit / delete / list; doc.open opens a cloud as a new design; selection.delete takes point_clouds; view bounds include them. - gpu: an instanced point-sprite pipeline (16 bytes a point). - ui: Browser Point Clouds folder with eyes, menu and an Edit Point Cloud card; drop, Open, Insert and file dialogs take .ply/.xyz/.pts; a CPU viewport fallback; messages in en, en-GB, ja, zh, de and ko. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Point clouds: colour by the file, one colour or height, from the UI (#5151) The Edit Point Cloud card gets Color By (File Colors, Single Color, Height). Height is a blue-to-red ramp over design Z, between the cloud's own two heights or, by default, a range worked out from the points (all but the lowest and highest 2 %, from an even sample). pointcloud.insert and pointcloud.edit take color_by and height_range; pointcloud.list reports them. The colour of each point is worked out in one place (PointCloud::shade) for the GPU and CPU viewports. Also: the card's dropdowns compare the picked index (a dropdown's response doesn't report the pick, so File Units did not change either). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Point clouds: integrate format registration and viewport caches (#5151) * Point clouds: satisfy current UI audits and document comparisons (#5151) Route model RGB data through the theme conversion boundary, provide a compact ribbon label, and include point clouds in the new document comparison. Gate the Unix-only CLI-link helper and test so Windows all-target checks remain buildable after the rebase. * Point clouds: isolate translations for current main (#5151) Move the existing 74 messages unchanged into one pending locale file and attribute it through a pending row, following the current repository workflow. Repository checks, 50 tooling tests, final workspace Clippy, wasm and generated-catalog equality checks passed after the rebase. * Point clouds: fit the rebased code to main's GpuTarget and Frame Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Compare point clouds when reusing placement-independent results Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Point clouds: complete command help and required translations (#5151) * Point clouds: size the save cap from the raised limit after the rebase Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
6b523d6839 |
Theme drops: build for the web, and import there too (#8226) (#8534)
DroppedFile::bytes exists only on native; the web build stopped at take_theme_drops. Native keeps reading the file there. On the web, the shell already reads every drop asynchronously before the app sees it: a drop over Preferences' Import tile now arrives as a theme and goes to prefs::import_theme_bytes, instead of being opened as a design. |
||
|
|
d7ef5280c5 |
Ctrl+W closes the design shown, not the browser tab (#5366) (#5466)
Ctrl+W (Cmd+W) closes the active design, asking first when it is unsaved; closing the last one shows the start page. In the web app a capture-phase keydown listener keeps the browser from closing the tab while a design is shown; on the start page the browser closes the tab. Ctrl+W joins the keys the app reserves, and the tab menu's Close shows it. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
dd2e44bb12 |
Raise the largest file SolidCraft opens with a setting or launch flag (#4086) (#7565)
* claim: #4086 * Raise the largest file SolidCraft opens with a setting or launch flag (#4086) * Translate the file size limit strings * Size limits: design files are .sc now, .solidcraft still read |
||
|
|
dba3a226f6 |
Closing from the background brings the window forward to ask about unsaved changes (#7783) (#7784)
* Closing from the background: the window comes forward to ask about unsaved changes Right-click › Close on the taskbar while another app had the focus showed the "save changes?" prompt in a window that stayed behind, so the close seemed to do nothing. When the close stops at the prompt, the window now asks for the focus (unminimizing it first) and for the user's attention, which is what native Wayland offers (xdg-activation) and marks the taskbar entry where the system refuses the focus. A window already in focus is left alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * X11: ask the window manager to raise the window as a user action winit's Focus asks as an application, which KWin's focus-stealing prevention refuses for a window last used before the switch away: it raised nothing and, since the attention request was then skipped, did not even mark the taskbar. On X11 send _NET_ACTIVE_WINDOW with source 2 (a direct user action) through x11rb, which restores a minimized window too; native Wayland keeps the attention request. Moves the logic into come_forward.rs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Come forward once the taskbar menu is gone, without flicker KWin raised the window, then the taskbar's closing context menu handed the focus back to the previous app 2 to 11 ms later, so the window only came forward some of the time; asking again made it flicker. Ask 120 ms after the close instead, and again only when the focus is taken back within 50 ms of a request (a slow menu) or never came. A later switch away is the user's own and the window stays behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8be7bb0201 |
Insert design: file names get the dialog's width (#8097) (#8122)
* claim: #8097 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Insert design: file names get the width the size and actions leave (#8097) The web app's "Files in this browser" window listed stored files in an egui Grid sized from cell content: the wide action buttons took most of the fixed window width, the name and size columns were cut, and the rest was empty. Add ui_kit::name_list on the kit's table grid: the name column takes the width the other columns leave, the other columns are as wide as their widest cell (measured as drawn, a changed measurement discards the frame), and a name is cut with an ellipsis and its full text on hover only when it does not fit. The window is a little wider (still capped at the browser width). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e181015fd1 |
MCP save: a folder the agent opened or saved a design in stays in scope (#7181) (#7216)
* claim: #7181 * MCP save: a folder the agent opened or saved a design in stays in scope (#7181) The agent's default folders held the open design's folder only while that design stayed open there, so after a new design, an opened STEP file or a save-as elsewhere a save beside the earlier design was refused, while the same save through the control port worked. The MCP server now keeps, for the rest of its run, the folder of every design file a call opened or saved (open, save, and doc.open, file.save, file.save_as through execute or batch, path given in full) and, headless, of every design open in its session. Such a call only succeeded because the folder was already in scope, so naming a path adds nothing. The folders get the open design folder's terms (inside home or temp, not hidden, hidden entries unreachable), at most 16. Bridged, they go to the app as design_folders, which it judges the same way. The save tool description and docs/mcp.md say how to add a folder with --allow-path. * MCP scope: a design's folder is the folder its file resolves to (#7181) A link in another folder to a design inside the agent's folders passes the scope check, which follows it, but its own folder was what got remembered (and, for the open design, what counted while it was open). Take the folder of the file as the check resolves it. * Control test: a hidden file the export format accepts (#7181) --------- Co-authored-by: MateuszSychXpl <151755914+MateuszSychXpl@users.noreply.github.com> |
||
|
|
03b8f4138b |
New designs save as .sc; .solidcraft files still open (#7325)
* claim: new designs save as .sc Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * New designs save as .sc; .solidcraft files still open and keep their name on Save DESIGN_EXT is now "sc"; DESIGN_EXTS lists sc, solidcraft and solvecraft and every open path (dialogs, drag-drop, recent files, CLI, MCP, links, the web picker) accepts all three. Save of an opened .solidcraft file writes that file; Save As, autosave, recovery and crash reports use .sc. Windows, macOS and Linux register .sc alongside the older extensions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Update UI tests for the .sc default extension Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
7a6c884418 |
Change the app id to io.tangencylabs.solidcraft, with aliases for existing installs (#7681)
The app id moves from ai.storyteller.solidcraft to io.tangencylabs.solidcraft: macOS bundle id (the CLI signs as io.tangencylabs.solidcraft.cli), Linux desktop/metainfo/MIME file names, icon name, Wayland app_id / X11 class, Flatpak, Snap common-id, nfpm/FreeBSD/Nix/AppImage staging, the web app's icon paths and the docs. Existing installs keep working: the Flatpak repository marks both old ids (ai.storyteller.solidcraft and ai.storyteller.solvecraft) end-of-life with a rebase straight to the new id, re-marking the solvecraft ref that pointed at the 0.8 id; the manifest grants read-only access to both old ~/.var/app folders and the first launch copies settings and autosaves from the newest one; AppStream <replaces>/<provides> and X-Flatpak-RenamedFrom list both; the AppImage removes menu entries it wrote under either old id. The data and settings folders (solidcraft / SolidCraft) are unchanged. The MSI UpgradeCode and ProgIDs are unchanged. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d2f0627421 |
Follow a theme file and reload it when it changes (#7573) (#7574)
* claim: #7573 * Follow a theme file and reload it when it changes (#7573) * Translate the follow-a-theme-file strings |
||
|
|
0d18757ed7 |
File dialogs open in the folder used last (#7756) (#7807)
* claim: #7756 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * File dialogs open in the folder used last (#7756) The desktop dialogs never said where to open, and the Linux ones then start in the home folder every time. Open, Insert, attach, Save As and Export now open in the folder of the file last chosen in a dialog, or of the open design when another design becomes the open one, whichever came last. Also fixes #7735. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9a7b657fdc |
Assistant: connect the last-used agent on startup (#7009) (#7124)
* claim: #7009 * Assistant: connect the last-used agent and open the panel at start (#7009) Two Settings > AI options, off by default: when SolidCraft starts, connect the agent started last (once the installed agents are known; a missing one is not swapped for another) and open the Assistant panel. Not for runs started with --control. A connection that never gets ready (no agent, start error, the agent ends while starting) is a new Failed state: the header reads Connection failed and Connect reads Retry. The control channel reports it as "failed" and takes connect_at_start / open_at_start. * Assistant: keep the start-up agent when a design replaces the blank one (#7009) Opening a design over the blank design SolidCraft starts with reset its chat and stopped the agent connected at start. A chat not asked anything yet now starts over in place and keeps its agent. Turning AI features off also drops a start-up connection still waiting for discovery. * i18n: Arabic, Hebrew and Vietnamese for the start-up options (#7009) ar, he and vi are complete catalogs on main now, so every new English message needs them. --------- Co-authored-by: MateuszSychXpl <151755914+MateuszSychXpl@users.noreply.github.com> |
||
|
|
2346c1ae81 |
Web app: Report a bug saves its screenshot as a download (#7192) (#7197)
* claim: #7192 * Web app: Report a bug saves its screenshot as a download (#7192) Save screenshot… wrote the PNG with image's save, that is std::fs, which the browser doesn't have. The screenshot is now encoded in memory and written through vfs, as every other save is, so the web app hands it out as a download. Natively the same file is written and ui.screenshot replies as before. A failed save says why in plain text instead of a Rust debug value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Web app: a screenshot without a path no longer panics (#7192) `ui.screenshot` without a `path` saved to `std::env::temp_dir()`, which panics on wasm32-unknown-unknown (std has no file system there), and the web app's control requests come through `window.solidcraft.request`. `vfs::temp_dir()` now returns `vfs::BROWSER_TEMP`, a folder of the in-memory files, in the browser, and `save_screenshot` and `vfs::design_folder_refusal` (reached when a request names `allow_paths` while a design is open) use it. Natively nothing changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Web app: keymap and theme exports download (#7192) Both exports wrote with `std::fs::write`, which always fails in the browser. They now write through `vfs::write` like the other saves, so the web app hands the file out as a download. Natively the file is the same; an agent's folder scope now applies to them as to every other write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: say what the folder-scope checks of the saves show (#7192) The screenshot test wraps the write in a folder scope by hand: that proves the write goes through vfs, not that ui.screenshot's write runs inside the request's scope. ui.screenshot checks the agent's folders when the request arrives; the PNG is written in a later frame, outside that scope, as on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |