Releases: hiroshiyui/rrcad
Releases · hiroshiyui/rrcad
v0.3.0
[0.3.0] - 2026-05-15
Added
- Hardware helpers — hole tools (
src/ruby/prelude.rb,
tests/phase8_tier2.rs): addedclearance_hole(size, depth:),
tap_drill(size, depth:),heat_set_insert(size, depth:),
socket_head_cbore(size, depth:, head_depth:), and
flat_head_csink(size, depth:, angle:)for:m2–:m5metric hardware,
each producing a cylinder/counterbore/countersink suitable for subtractive
modelling with.cut. - Hardware helpers — bearing bores (
src/ruby/prelude.rb,
tests/phase8_tier2.rs):bearing_bore(size, depth:, fit:)produces an
outer-diameter bore for common deep-groove ball bearings (:b608,:b623,
:b624,:b625,:b626,:b688,:b695,:b6000,:b6001, or a numeric
OD), with:press(interference) or:slip(clearance) fit. - Hardware helpers — shaft fits (
src/ruby/prelude.rb,
tests/phase8_tier2.rs):shaft(diameter, length:, fit:)generates a solid
mating shaft cylinder with:nominal,:press,:slip, or:runningfit
adjustments relative to the nominal diameter. - Hardware helpers — standard fasteners (
src/ruby/prelude.rb,
tests/phase8_tier2.rs):screw(size, length:, style:)generates solid
fastener bodies for:m2–:m5in:socket(ISO 4762),:button
(ISO 7380), and:flat(ISO 10642 90° conical head) styles. - Sketch — tangent constraint (
src/ruby/prelude.rb,
tests/phase10_sketch_constraints.rs):tangent(a, b, center, radius, side:)constrains a line segment tangent to a circle. Withside:
(:above/:belowfor horizontal lines,:left/:rightfor vertical
lines) the solver propagates the unknown perpendicular coordinate on
either the line or the center; for fully-resolved geometry it verifies the
point-to-line distance and raises on conflict. Endpoint-driven orientation
inference lets the constraint work inside open rectangle sketches. - Assembly — transform-based constraint helpers (
src/ruby/prelude.rb,
tests/assembly_constraints.rs):Shape#rotate_about(point, axis_dir, angle_deg)rotates around any pivot;Assembly#distance_mate(shape, from:, to:, distance:)is a named air-gap variant ofmate;
Assembly#axis_align(shape, from: [p1, p2], to: [q1, q2])rotates and
translates a shape so a source axis maps to a target axis (covers
coaxial / concentric / axis-alignment cases);Assembly#angle_mate(..., angle:, pivot:, axis_dir:, offset:)mates a face flush and then rotates
about a chosen pivot axis to lock the leftover rotational degree of
freedom. - Sketch — solver diagnostics enriched (
src/ruby/prelude.rb,
tests/phase10_sketch_constraints.rs): conflict messages now name the
involved sketch points and report the actual vs expected values
(horizontal/vertical/coincident/dimension/equal_length/
tangentand anyassign_coord-driven constraint); the "did not
converge" failure lists every unresolved point with its missing
coordinates. The original"conflicting X constraint"substring is
preserved at the start of each message for backward-compatible matching. - Sketch — polar_point construction helper (
src/ruby/prelude.rb,
tests/phase10_sketch_constraints.rs):polar_point([:name,] center, radius, angle_deg)registers a construction point at polar coordinates
aroundcenter; oncecenterresolves the solver derives(cx + r·cos θ, cy + r·sin θ). Useful for bolt circles and angular layouts.
Closes the constraint-based-sketching MVP entry indoc/TODOs.md. - CAM / 3-D printing — mass and build-volume helpers
(src/ruby/prelude.rb,tests/cam_checks.rs):
mass_estimate(part, density: 1.24)computes a rough mass in grams from
part.volume × density / 1000;print_volume_check(part, x:, y:, z:)
reports{fits:, dx:, dy:, dz:, overflow_x/y/z:}against a rectangular
build volume. - CAM / 3-D printing — face normals exposed + overhang_faces
(src/occt/bridge.{h,cpp},src/occt/mod.rs,src/ruby/native.rs,
src/ruby/glue.c,src/ruby/prelude.rb,tests/cam_checks.rs): new
shape_face_normalbridge call samples the outward unit normal at the
face's parameter-space midpoint viaBRepLProp_SLProps, flipping for
TopAbs_REVERSEDfaces; surfaced to Ruby asShape#normalreturning
[nx, ny, nz]. Built on top:overhang_faces(part, max_angle_deg: 45)
lists faces whose outward normal tips below a horizontal threshold
(assumes +Z-up build direction). - CAM / 3-D printing — draft analysis (
src/ruby/prelude.rb,
tests/cam_checks.rs):draft_faces(part, axis: [0, 0, 1], min_draft_deg: 1.0)lists faces with insufficient mould draft along the
pull axis (asin(|n·axis|) < min_draft_deg). Top/bottom faces are
naturally excluded; the pull direction is configurable so non-Z pull
setups work without rotation tricks. - CAM / 3-D printing — hole orientation analysis
(src/occt/bridge.{h,cpp},src/occt/mod.rs,src/ruby/native.rs,
src/ruby/glue.c,src/ruby/prelude.rb,tests/cam_checks.rs): new
shape_cylinder_axisbridge call extracts the axis (origin + unit
direction) and radius of cylindrical faces via
BRepAdaptor_Surface::Cylinder(). Surfaced to Ruby as
Shape#cylinder_axisreturning{origin:, axis:, radius:}. Built on
top:hole_axes(part, orientation: :vertical | :horizontal, tolerance_deg:)enumerates and filters cylindrical faces by axis
direction. - OCCT diagnostics — call-site context + actionable hints
(src/occt/mod.rs,tests/error_diagnostics.rs): errors from
Boolean ops (fuse/cut/common), fillets and chamfers (including
selector / variable-radius / asymmetric variants),
extrude/revolve/shell/offset/offset_2d/simplify,
sweep/sweep_guide/sweep_sections,loft, Part Design (pad,
pocket), and import/export now lead with the operation name, its
numeric parameters, the operand shape kind (via asummarize()
helper), and any file path or view name. The most common failures
(fillet/chamferradius too large,extrudeon a solid,shell
thickness too thick,pad/pocketplanar-face requirement,
sweep/sweep_guideprofile-and-path types,
import_step/import_stlmissing files) also carry an actionable
one-linehint: …suffix. The original"X failed: …"substring is
preserved so existing substring matchers keep working.
Fixed
- CI — install g++ explicitly (
.github/workflows/rust.yml):
Debian sid'sgccmeta-package no longer pullsg++as a transitive
dependency, so the CI container was missing a C++ compiler and
link-cplusplus/ cxx bridge builds failed withfailed to find tool "c++". Addg++to the apt install line.
v0.2.2
Security
- MCP timeouts are now process-enforced (
src/mcp/mod.rs,src/main.rs): MCP tool evaluations run in one-shot worker processes that are killed when the 30 s timeout expires. A runaway Ruby loop or long OCCT operation can no longer keep running on a blocking thread after the client receives a timeout. - MCP prelude hardening extended (
src/mcp/mod.rs): the production security prelude now removes additional metaprogramming entry points fromBasicObject,Object,Kernel, andModule, including top-leveldefine_method, closing a dev-build escape path caught by the expanded integration tests.
Changed
- MCP tests use production hardening (
tests/mcp_tools.rs,tests/mcp_stress.rs): integration and stress tests now construct MCP VMs through the real production helper instead of carrying a stale copied prelude, and cover blocked file-access and metaprogramming methods. - Dependency audit rationale documented (
audit.toml): accepted the transitiverandadvisory (RUSTSEC-2026-0097) with the project-specific rationale pending an upstream axum/tungstenite update. - Agent repository guidance added (
AGENTS.md): documented project layout, build/test commands, coding style, testing expectations, and agent-specific instructions for future automation.
v0.2.1
[0.2.1] - 2026-05-12
Security
- MCP prelude: undef metaprogramming methods (
src/mcp/mod.rs): the runtime
security prelude now also stripseval,instance_eval,class_eval,
module_eval,send,__send__,public_send,method,define_method,
define_singleton_method, andbindingfromKernel. Production builds
withmcp_safe.gemboxwere already safe, but a development build using the
default gembox could previously reach undef'd methods viasendoreval.
The loop now runs insideKernel.module_eval { … }so undef'ing:send
mid-iteration cannot break the loop itself. - CLI preview tempfile uses CSPRNG (
src/main.rs): the temporary GLB
filename is now derived fromuuid::Uuid::new_v4()(122 bits of OS-CSPRNG
entropy) instead ofDefaultHasher(time, pid). The previous path was
predictable from PID plus approximate launch time, weakening the symlink-
attack mitigation.
Fixed
- Preview server start now returns
Result(src/preview/mod.rs,
src/main.rs):preview::startno longer panics on double-init or tokio
runtime creation failure — the CLI prints a clear error and exits cleanly. - MCP preview port-init race (
src/mcp/mod.rs):MCP_PREVIEW_PORT
switched fromstd::sync::OnceLocktotokio::sync::OnceCellwith
get_or_try_init. Two concurrent first-timecad_previewcalls could
previously each bind a listener and spawn an axum task — only one won the
OnceLock::set, leaking the loser's listener and task. The async OnceCell
serialises initialisation so only one initialiser runs. - Preview WebSocket reconnect storm (
src/preview/viewer.html): the
browser previously retried every 1 s forever after rrcad exited, pounding a
dead port. Reconnect now uses exponential backoff (1 → 2 → 4 → 8 s, capped
at 8 attempts) and ends with a clear"server gone (reload page to retry)"
status. - Preview GLB-load error detail (
src/preview/viewer.html): the load-
error status line now includes the underlying error message instead of the
bare"load error"text, making failures self-diagnosable from the browser. - Clippy lints:
items_after_test_moduleinsrc/main.rs(helpers moved
above the test module),useless_vecintests/phase5_params.rs, and
len_zerointests/e2e_dsl.rs.
Changed
- REPL tab-completion:
SHAPE_METHODSinsrc/main.rsextended with
fillet_var,bounding_box,volume,surface_area,distance_to,
inertia, andmin_thicknessso autocomplete matches the documented and
available native methods. - Documentation:
CLAUDE.mdupdated to reflect the per-process randomised
CLI preview tempfile and the MCP/tmp/rrcad_mcp/preview.glbpath, and to
list the/logo.pngaxum route.src/preview/server.rsmodule doc lists
/logo.png.
v0.2.0
Added
- Preview: flat-line view: press
Fto toggle flat-line rendering — white flat-shaded surfaces with heavy-gray edge lines drawn at ≥15° creases. View mode persists across live-reloads. - Preview: hamburger menu: top-right menu button with three sections — View (Normal / Flat-line), Scene (Showroom / White), and Show (Axes). Keyboard shortcuts (
F,A) stay in sync. PressEscapeto close. - Preview: white scene: pure-white inspection scene preset — white background, white floor, flat neutral lighting, no vignette. The dark Showroom scene remains the default.
Fixed
- Preview: GPU memory leaks: outgoing model geometries disposed on each live-reload, preventing unbounded GPU memory growth.
- Preview: GLB load-error message: error callback now shows
"rrcad preview — load error"and logs to console (previously showed "waiting for model"). - Preview: F shortcut ambiguity:
Fshortcut shown only on the inactive view menu item. - MCP server: sandbox directory permissions: sandbox created with
0o700(user-only), eliminating a TOCTOU window. - MCP server: prelude blocks additional methods:
open,require,require_relative, andloadare now removed fromKernelin the security prelude. - glue.c: malloc leak on mRuby raise: multi-shape operations now use
mrb_data_check_get_ptrwith free-before-raise to avoid leaking pointer arrays. - bridge.cpp: std::exception escape: added catch clause so non-OCCT C++ exceptions cannot silently cross the
cxxboundary.
Security
- MCP prelude now blocks
open,require,require_relative, andloadin addition tosystem,exec,`, andeval. - Sandbox directory created with
0o700permissions (was world-readable until chmod).
v0.1.6
Changed
- Preview: studio photography look (
src/preview/viewer.html): transformed the live viewer into a dark product-photography studio — vertical gradient background (cool dark top → faintly warm bottom), a large polished studio floor plane that catches shadows and shows faint model reflection, multi-light rig (key/fill/rim/bounce), 40° telephoto FOV (less distortion than 45°), CSS vignette overlay for cinematic corners, per-model shadow frustum fitted to bounding box for crisp shadows, orbit floor clamp so the camera cannot go below the studio floor, axes helper (press A to toggle), and ACES filmic tone mapping at 1.2× exposure. - Preview: tighter camera fit (
src/preview/viewer.html):fitCameramultipliers reduced from 2.5 × 1.4 to 1.15 × 1.0, so the model fills the frame closely on every load rather than sitting in a wide empty viewport. - Split TKL keyboard — flat-bottom case (
samples/split_tkl_keyboard.rb): removed thesolid_tentwedge base entirely. The case now has a flat bottom; users glue on custom-printed tenting feet at whatever angle they prefer. - Split TKL keyboard — right bottom-row modifiers widened (
samples/split_tkl_keyboard.rb): RAlt, Fn, and RCtrl widened from 1 U to 1.25 U each; Space repositioned to 1 U at the left edge of the row (flush with the case wall) so all three modifiers pack tightly against the spacebar. Leaves a natural 1.25 U gap before the arrow cluster.
Fixed
- Split TKL keyboard — RShift position corrected (
samples/split_tkl_keyboard.rb): RShift switch centre moved from 5.5 U to 6.0 U so the 2 U keycap sits flush against/on the left (both edges at 5.0 U) and flush against Up ↑ on the right (both edges at 7.0 U). The previous 5.5 U position caused the RShift keycap to overlap/by 0.5 U. - Preview: zoom limits removed (
src/preview/viewer.html):minDistanceandmaxDistanceconstraints onOrbitControlswere removed so the camera can orbit right up to the model surface for close-up detail inspection. - CLI: script paths outside working directory (
src/main.rs): thesafe_pathCWD restriction on the input script argument was overly strict for CLI use — users should be able to runrrcad --preview ../mykb/script.rbor any absolute path. Removed the guard fromrun_script,run_preview, andrun_table; export paths produced inside scripts remain confined bysafe_pathinnative.rs. - Split TKL keyboard sample (
samples/split_tkl_keyboard.rb): replaced fraction-based pillar positions with diagonal midpoints between 4 adjacent key centres, giving ~13.5 mm clearance from every switch body edge (previously the positions fell directly under Cherry MX switch bodies and inside the Raspberry Pi Pico board footprints). Both halves now have 4 pillars each.
v0.1.5
Fixed
- MCP server: SIGSEGV from concurrent mRuby VMs —
spawn_blockingruns closures on a thread pool, so a timed-out tool call could leave a mRuby VM alive on one thread while a second call spawned a new VM on another. mRuby is not thread-safe; concurrent VMs caused SIGSEGV crashes. A newMRUBY_EVAL_LOCK(std::sync::Mutex<()>) is now acquired at the top of everyspawn_blockingclosure, serialising all mRuby/OCCT work regardless of how many concurrent calls arrive or how many timed-out threads are still running. - MCP server: TOCTOU port-binding race in
cad_preview— the old code bound a listener to discover a free port, dropped it, then had axum try to rebind the same port. Another process could steal the port in that window, causing apanic!inside the spawned task. Thetokio::net::TcpListeneris now kept alive and passed directly to a newserve_with_listener()on the axum server, eliminating both the race and a 200 ms sleep. - Split TKL keyboard sample (
samples/split_tkl_keyboard.rb): added M2.5 button-head counterbores (Ø4.8 mm, 1.5 mm deep) to all plate screw vias so screw heads sit flush with the plate top face.
Changed
- Split TKL keyboard — connectors, bosses, and manufacturing details (
samples/split_tkl_keyboard.rb):- Replaced RJ-45 inter-half connector with USB-C (safer for hot-plug; no VCC on interconnect cable). Left half: USB Micro host port at back wall ¼-width + USB-C interconnect at ¾-width. Right half: USB-C interconnect at ¼-width + USB-C host port at ¾-width.
- Added wall slots for USB-C adapter boards (12×4.2 mm PCB, open-top insertion pocket, 9×3.5 mm USB-C port opening in back wall).
- Upgraded corner and mid-edge screw bosses to M2.5 heat-set copper insert compatibility (POST_R 2.5 → 3.2 mm, M2_R 1.2 → 1.6 mm; 3D print FIT_TOL 0.2 mm per side).
- Added bottom-face lead-in step (0.5 mm box-cut method) on all switch cutouts to ease Cherry MX switch clip insertion from below.
- Added
CHAMFER_CASEchamfer to the solid tent wedge base (applied before fusing with the tilted case half to avoid BRepFilletAPI_MakeChamfer failures on complex fused geometry). - Preview changed from 2×2 parts layout to a fully assembled side-by-side view (plates seated in cases, left and right halves with a 20 mm gap).
Added
- MCP stress tests (
tests/mcp_stress.rs): 10 new tests covering sequential VM churn, error recovery, boundary inputs, deep boolean chains, geometry validation after operations, security prelude persistence, and a two-thread lock-serialisation proof.
v0.1.4
Changed
- Split TKL keyboard layout refinements (
samples/split_tkl_keyboard.rb):- Left Fn row (F1–F6) aligned with number row (` 1–6) while maintaining proper Tab/Home/Shift row key widths (1.5U, 1.75U, 2.25U respectively)
- RJ-45 Ethernet ports repositioned to symmetrical 1/4-width positions on both left and right cases (mirrors USB positioning)
v0.1.3
Added
- Split TKL keyboard sample (
samples/split_tkl_keyboard.rb): complete 86-key split TKL mechanical keyboard (Cherry MX, 19.05 mm pitch) with a compact right half (≈20.7 cm) that fits a 22 cm print bed. Layout features: single nav column, inverted-T arrow cluster on the bottom row, PrtSc/ScrLk/Pause on the Fn row alongside F7–F12. - M2.5 heat-set insert standoffs for Raspberry Pi Pico mounting (4 bosses per side, 4 mm tall, 3.2 mm Ø press-fit holes). Left Pico rotated 90° so the micro-USB port faces the back wall; USB cutout Z-offset raised to align with the Pico PCB level.
- Mid-edge M2 screw bosses (2 per side) at verified switch-cutout-clear edge positions to improve plate–case rigidity beyond the four corner screws.
- Central screw-less support pillar (1 per side) at the plate midpoint — a solid post rising to 0.2 mm below the plate underside to resist flex under typing load without requiring a via hole through the plate.
doc/split_tkl_keyboard.stl— 2×2 preview layout (cases + plates) for interactive 3D viewing on GitHub.
v0.1.2
Added
- Schmidt ball pen sample (
samples/pen_schmidt.rb): four-part pen body (barrel, tip, front cap, tail cap) demonstratingcone,rotate, boolean ops, and multi-part layout. Tip-to-barrel joint uses an L-shaped tenon & mortise (quarter-turn bayonet) with spring-relief cantilever tabs for tactile snap-fit installation. Exports STEP and STL.
Changed
- Preview render quality (
src/preview/viewer.html): replaced the ad-hoc three-directional-light rig (including a blue fill that caused unnatural colour casts) with ACES filmic tone mapping, aRoomEnvironmentPBR ambient map, aHemisphereLight(cool sky / warm ground), and a single clean key light. Shadows upgraded toPCFSoftShadowMapat 2048 × 2048 with bias to eliminate shadow acne.
Fixed
set_params()backslash injection (src/ruby/vm.rs): only double-quotes were escaped when building the$_rrcad_paramsRuby hash literal from--paramCLI values. A backslash in a value (e.g.--param path=C:\dir) produced an unterminated string literal. Backslashes are now escaped before double-quotes.- Memory-limit doc discrepancy (
src/mcp/mod.rs): module-level table said512 MBbut the constant is2 GB. Updated to match actual value and clarified that the limit is applied once instart(), not per-call.
v0.1.1
What's Changed
Fixed
MRUBY_CONFIGpath doubling: mruby's Rakefile already prepends
build_config/when resolvingMRUBY_CONFIG, so passing
build_config/rrcadproducedbuild_config/build_config/rrcad.rband
broke every CI build from scratch. Fixed by passing the bare namerrcad.
The bug was masked locally by the cachedlibmruby.a.- Missing
mruby-compilerinmcp_safegembox:mrb_load_string()—
used byglue.cto evaluate DSL strings — is implemented in the
mruby-compilercore gem, not in mruby's base C library. Omitting it
caused a linker error on all clean builds.mruby-compiler(C-level
parser) is distinct frommruby-eval(Ruby-levelKernel#eval), which
remains excluded.
Changed
- Added
scripts/clean-build.shand apre-pushgit hook that
automatically runs a clean mruby build whenbuild.rsor
mruby_configs/are in the outgoing commits, catching build-plumbing
bugs before they reach CI.
Full changelog: https://github.com/hiroshiyui/rrcad/blob/main/CHANGELOG.md