Commit graph cad-editor/Cargo.lock
Author SHA1 Message Date
Hakan Seven
e3c9e538e2 release: v0.5.8
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 01:37:20 +03:00
Hakan Seven
fefae274d4 feat(wasm): web Save/Save As go through the dialog with a direct download
On the web, Save and Save As now open the in-app Save dialog (filename +
format) like the desktop, and the unsaved-changes prompt's Save routes
through it too — instead of an immediate rfd download. Confirm serializes
to bytes and downloads directly via a Blob + hidden `<a download>` click
(a user gesture), so there is no intermediate "click to download" link.

Replaces the rfd-based download_web / WebSaveResult round-trip with a
synchronous sys::download_bytes. Native save is unchanged.

Native + web build; 75 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 00:52:20 +03:00
Hakan Seven
93d136c5db fix: Donate button (Start tab gate + web window.open)
- Add DONATE to the Start-tab command allowlist; it was blocked there
  with "No drawing open" while REPORT/CHANGELOG/ABOUT were allowed, so
  the Donate button did nothing on the welcome screen.
- Implement sys::open_url on wasm via web_sys window.open(_blank) — it
  was a no-op stub, so Donate, Release Notes and Send Feedback opened
  nothing on the web. The click is a user gesture, so the pop-up blocker
  allows it.

Native + web build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 00:27:33 +03:00
Hakan Seven
c49ad887b8 fix(wasm): make the web build actually run in the browser
With the wasm bundle building, get it rendering in a browser:

- Enable iced `webgl` so wgpu uses WebGL2 where WebGPU is absent
  (e.g. Firefox by default), and `fira-sans` so UI text has an
  embedded font (the web has no system fonts) — without it every
  label was blank.
- Replace `std::time::Instant` with `iced::time::Instant` (web-safe);
  `Instant::now()` panics ("time not implemented") on wasm and crashed
  at boot via the command line.
- Skip the batched-hatch pipeline on wasm: its bind group needs
  vertex-stage storage buffers, which WebGL2 lacks (validation error
  on "New drawing"). Fields become Option; upload/draw guard on them.
  Hatches don't draw on the web for now; everything else does.
- Fix the trunk feature flag (`data-cargo-no-default-features`) and
  ignore the `dist/` build output.

Native build + 75 tests unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 17:53:56 +03:00
Hakan Seven
157d54a4d4 feat(wasm): single-window web entry + trunk harness (issue #45)
The binary now compiles for wasm32 as a runnable web target:

- Split the main-window render into `view_main`, bypassing the
  multi-window id dispatch the browser cannot use.
- Add `run_web` / `boot_web`: a single-window `iced::application`
  entry for wasm (the browser canvas is the only window). Native
  keeps the multi-window `iced::daemon` via cfg-split in `main`.
- Add a `console_error_panic_hook` (wasm-only) for readable panics.
- Add `index.html` + `Trunk.toml` so `trunk serve` builds the wasm
  bundle (no-default-features → no solid3d) with COOP/COEP headers.

Native build and all 75 tests unchanged. Browser runtime (rayon
threads, canvas attach, real file I/O) is the next iteration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 13:16:35 +03:00
Hakan Seven
cd048165a9 feat(fonts): system TrueType support with shaping and fallback
Add a TrueType/OpenType render path alongside the LFF stroke engine so
users can pick fonts installed on their machine for text and MText.

- Discover system families via fontdb (sysfont) and list them in the
  text-style picker.
- Extract glyph outlines with ttf-parser, flattened into wire strokes
  normalized to the same 9-unit cap-height space as LFF glyphs.
- Shape runs with cosmic-text (ligatures, Arabic joining, kerning, bidi)
  plus automatic font fallback: a glyph missing from the chosen family
  is taken from another installed font.
- Unify both sources behind a single Face type; a shared run tokenizer
  drives the stroke (per-glyph) and shaped (TTF) renderers identically.
- Stroke fonts now fall back to a system TTF (cosmic-text picks it) for
  characters no LFF font covers, replacing the unicode/iso3098 chain.

Also trim the embedded LFF set from 47 to 26, keeping the AutoCAD-SHX
equivalents and dropping LibreCAD-only fonts now covered by TrueType.

LFF builtins keep priority over same-named system fonts so DXF text
renders identically across machines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 11:18:17 +03:00
Hakan Seven
1d4243ba7e chore(release): bump to 0.5.7
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 04:30:27 +03:00
Hakan Seven
084dfb1bdb fix(windows): embed the app icon into the .exe
The Windows executable carried no icon, so Explorer, the taskbar, the
Start-menu tile and file-association entries showed a generic icon. Embed
AppIcon.ico via winresource in build.rs, and generate the .ico from the logo
before the build (it was produced after the build, too late to embed). Local
and non-Windows builds skip the step when the .ico is absent.

Fixes #107.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 04:10:01 +03:00
Hakan Seven
25bf371290 fix(menu): close the main menu when opening a recent file
The recent-file buttons dispatched the open command without closing the app
menu, so it stayed open over the loaded drawing. Use CloseAppMenuAndRun so the
menu closes first, matching the other menu entries. Also commits the Cargo.lock
update from dropping iced's debug feature.

Fixes #103.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 03:51:45 +03:00
Hakan Seven
dd1ec3ad40 feat(xclip): clip block references to their SPATIAL_FILTER boundary
Block references carrying an XCLIP spatial filter were drawn in full,
ignoring the clip boundary. Resolve the filter through the INSERT's
extension dictionary (ACAD_FILTER -> SPATIAL) and clip the expanded
block geometry to the boundary polygon: polylines are split into the
inside runs, fill triangles are clipped, and snap/key vertices outside
the boundary are dropped.

The boundary vertices live in the clip-definition space, so they are
placed with world = T_insert * (inverse_block_transform * vert); this
keeps the clip correct even when the insert was rescaled after the clip
was created. Bumps acadrust to the build that decodes SPATIAL_FILTER.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:29:10 +03:00
Hakan Seven
72ec1146df refactor(plugin): extract ocs_plugin_api crate for the stable add-on contract
Move the dependency-free, semver-versioned half of the plugin contract into a
standalone workspace crate `crates/ocs_plugin_api`:

- manifest types: PluginManifest, ApiVersion, API_VERSION
- ribbon vocabulary: CadModule trait + ToolDef/RibbonGroup/RibbonItem/IconKind/
  ModuleEvent/StyleKey

The host re-exports them from `crate::plugin::manifest` and `crate::modules`, so
every existing call site is unchanged. The acadrust-typed runtime surface
(HostSession) stays in the host binary; lifting it behind a HostApi trait in the
same crate is the remaining phase-1b step.

Part of #100. Docs updated in docs/plugin-architecture.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 01:36:04 +03:00
Hakan Seven
7a4ddbc62e chore(release): bump to 0.5.6
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 01:33:55 +03:00
Hakan Seven
9d823363f1 feat(scene): render 3D surface entities (loft/sweep/extrude/etc.)
ACAD_SURFACE entities now load and render. Their NURBS faces are
tessellated by building a truck BSplineSurface from the ACIS `spline-surface`
control net and knot vectors, then sampling its parametric grid — reusing the
same NURBS kernel the Model tab already builds on. Analytic faces
(plane/cone/sphere/torus) continue through the existing tessellator.

- New spline_tess.rs: parse the ACIS `nubs` block (degrees, knots with the
  clamped end-multiplicity fix, control grid) into a truck BSplineSurface and
  mesh it.
- tessellate_surface + Surface wired through the mesh-build, fallback-wire,
  and entity-classification paths.
- Bump acadrust to the commit that adds the Surface entity.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 20:11:44 +03:00
Hakan Seven
dfb2c6f9d7 chore(release): bump to 0.5.5
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 11:20:18 +03:00
Hakan Seven
006dbe4631 fix(dimension): make DIMTAD/DIMTVP/DIMJUST drive text placement (#94)
Dimension text position ignored the style: the renderer returned the
saved text_middle_point whenever it was non-zero, which it always is for
app-created dims, so DIMTAD ("text over the dimension line" / ISO) and
friends had no effect — text could only be moved by grips.

Use the new acadrust text_user_positioned flag: when the text wasn't
user-placed, compute the position from the style (DIMTAD/DIMTVP/DIMJUST)
anchored on the dimension line (definition_point); when it was (grip drag
or properties edit, both now set the flag), keep the saved point.
Imported drawings keep their fidelity via the flag round-tripping through
DXF/DWG.

Also fixes linear/aligned text anchoring at the measured midpoint instead
of the actual dimension line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 01:57:58 +03:00
Hakan Seven
37ef813814 chore(release): bump to 0.5.4
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 14:21:02 +03:00
Hakan Seven
c9071579a2 chore: release v0.5.3 2026-06-12 01:48:34 +03:00
Hakan Seven
e68f95aff2 chore: bump acadrust — decode SAB Position tokens
Binary (SAB/ASM) solids no longer collapse every vertex to the origin,
so 3D solids from AutoCAD 2013+ render with real geometry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 23:48:44 +03:00
Hakan Seven
572415485e chore: bump acadrust — 3DSOLID AcDs geometry loading
Loads ACIS/ASM modeler geometry for 3DSOLID/REGION/BODY from the AcDs
data store (AutoCAD 2013+), so solids stored there now render instead of
coming through empty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 23:38:31 +03:00
Hakan Seven
1f54b1241f chore: bump acadrust — dynamic-block visibility parsing
Brings in AcDbBlockVisibilityParameter / AcDbBlockRepresentationData
parsing and the dynamic_visibility_for_insert resolver, the foundation
for the upcoming visibility-state UI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 19:44:53 +03:00
Hakan Seven
ece5d50796 chore: bump acadrust to current main
Picks up the AC18 section-name fix (cut at first null), so DWGs whose
writer left garbage after the name terminator load their entities
instead of opening with zero. Also rolls in the intervening upstream
ellipse-WCS and reflecting-transform fixes already on main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 17:28:21 +03:00
Hakan Seven
8f39e77a0d chore: release v0.5.2 2026-06-11 14:41:24 +03:00
Hakan Seven
6d60ef45d5 fix(hatch): wrong-way giant boundary arcs in blocks — bump acadrust
Hatches inside blocks (xref_Plan-Sade) drew some boundary arcs as their
near-full-circle complement, covering huge areas — in the pattern clip
when rendered through the INSERT, and in both pattern and boundary wires
after EXPLODE.

Root cause (acadrust 64efaf8): the stored sweep of a boundary arc is
always forward and AutoCAD encodes a wrap through 0 by writing the end
angle ABOVE 2π (5.81 → 6.64 for a 0.83 rad arc). transform_hatch
normalized angles into [0, 2π), turning such arcs into their 5.46 rad
complement on ANY insert pass-through — even a pure translation, which
is why the same hatch looked fine outside the block. The fix transforms
only the start angle and carries the stored sweep over unchanged
(invariant under rotation and mirror); RAW vs exploded edge angles are
now bit-identical on the reporting file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 01:01:56 +03:00
Hakan Seven
14b5067e25 fix(hatch): mirrored-block arcs — bump acadrust, document angle convention
Hatches inside mirrored INSERTs (x_scale = -1, e.g. the *U blocks in
xref_Plan-Sade) drew some boundary arcs swept the wrong way, covering
huge complementary regions — in the pattern clip before EXPLODE, and in
both pattern and boundary wires after (the exploded entity bakes the
broken angles).

Root cause was in acadrust's transform_hatch, not the renderer: DXF
stores CW (ccw=false) boundary-arc angles MIRRORED (verified against
AutoCAD output by endpoint continuity — mirrored interpretation gives
Δ=0.0 against adjacent edges), and the transform stored geometric angles
after flipping the direction flag. The legacy (TAU-θ) sampling flip in
arc_signed_span is exactly right for file data and stays; its comment now
records the verification so the convention isn't "fixed" away again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 00:41:16 +03:00
Hakan Seven
31cdd6632f chore: bump acadrust to current main (upstream sync)
Picks up the fork's merge of upstream acadrust (geodata decode, DXF
roundtrip newline sanitization, DWG alignment) on top of the current
table/multileader style work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 19:09:46 +03:00
Hakan Seven
e65a7a6d67 feat(styles): seed current table/multileader style from the file
Bump acadrust to pick up the new $CTABLESTYLE / $CMLEADERSTYLE header
variables, then on load seed the ribbon's active table style and the
tab's active multileader style from the document header so the ✓ marks
the style the file actually declares (DXF). Set Current writes the header
field as the round-trip source of truth, and the style-manager staging
snapshot now covers it. sync_ribbon_styles honours the active table style
instead of always falling back to the first one.

DWG still leaves these at "Standard" until acadrust parses them from the
binary header.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 19:05:07 +03:00
Hakan Seven
fb9f5bd4e5 chore(release): bump to 0.5.1
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:00:46 +03:00
Hakan Seven
7f94a9d66a chore(release): bump to 0.5.0
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 15:35:08 +03:00
Hakan Seven
70702d063f perf(hash): swap std HashMap/HashSet for rustc-hash FxHash
Phase 4.1. Handle / u64 keys dominate the hot maps (block_defn,
hatch / image / mesh caches, draw-depth map, viewport wire caches);
the default SipHash is wasted work on integer keys. Alias the std
types to rustc_hash::FxHashMap / FxHashSet crate-wide so every map and
set — including the cross-module draw-depth map shared between scene
and the GPU pipelines — uses the faster hasher consistently.

Mechanical: no behavioural change. Constructors moved from ::new() to
::default() (Fx variants carry no RandomState). Build + 13 tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:35:53 +03:00
Hakan Seven
b466747074 chore(release): v0.4.9
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:14:47 +03:00
Hakan Seven
edc8cbc969 feat(scale): drive scales from the drawing's scale list
Read the model-space annotation scale from the standard CANNOSCALE /
CANNOSCALEVALUE header variables instead of a user-variable hack, and
populate both the status-bar scale picker and the viewport Scale
property purely from the drawing's ACAD_SCALELIST — no built-in
fallback set. Xref-derived scales (`_XREF` suffix, `name|` prefix)
are filtered out so only the host drawing's own scales appear.

Bumps the patched acadrust to the commit that adds CANNOSCALE/
CANNOSCALEVALUE read/write.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 16:18:01 +03:00
Hakan Seven
8699a730bf chore(release): v0.4.8
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 11:40:16 +03:00
Hakan Seven
e708f90517 fix(macos): statically link liblzma so the app launches (#56)
vtkio (via truck-meshalgo → xz2 → lzma-sys) linked the system liblzma
dynamically, baking a Homebrew path (/opt/homebrew/.../liblzma.5.dylib)
into the macOS binary. The .app then crashed on launch on any Mac
without that exact library. Enable lzma-sys's `static` feature so
liblzma is compiled from the bundled source into the binary, making it
self-contained on every platform (verified: no dynamic liblzma link).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 02:34:56 +03:00
Hakan Seven
90c9ac62c8 chore(deps): bump acadrust for DWG annotative (AcadAnnotative EED)
Picks up 5352477: STYLE/DIMSTYLE annotative now round-trips through DWG
via AcadAnnotative EED (ODA-spec encoding), matching the DXF side.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 01:47:04 +03:00
Hakan Seven
2c24f357e1 chore(deps): bump acadrust to standard-compliant annotative IO
Picks up bc711f0: annotative is now persisted the standard way
(AcadAnnotative XDATA for STYLE/DIMSTYLE/TABLESTYLE, native group 296 +
DWG bit for MLEADERSTYLE), superseding the earlier non-standard marker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 01:29:39 +03:00
Hakan Seven
94b4d536f1 fix(styles): use allocate_handle for new style records
Creating a new MLeader/Table/MLine style (and a new PlotSettings) pulled
the document's next handle without advancing the counter, so two records
created in one session collided on the same handle and the second
overwrote the first. Use allocate_handle(), which reserves and advances.

Also bumps acadrust to pick up DXF annotative-flag persistence.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 01:00:26 +03:00
Hakan Seven
52850947d2 feat(textstyle): full Text Style editor — big/TT font, fixed height, flags, annotative
Expands the Text Style manager beyond font/width/oblique: big-font and
TrueType font fields, fixed text height, Backward / Upside-down flags, and
an Annotative toggle (applied live). Bumps acadrust for the annotative
field.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 17:43:12 +03:00
Hakan Seven
f0b11acc88 feat(viewport): per-tile model render mode, persisted via VPORT entries
Each model-space tile now carries its own visual style instead of one
global mode shared by every pane:

- ModelTile gains a `render_mode`; the active tile renders with the live
  picker mode, inactive tiles keep their stored style, so changing one
  tile no longer changes the others. Split inherits the source style.
- SetRenderMode writes only the active tile; switching the active tile
  mirrors its style back into the tab (picker + live render).
- Persisted through the *Active VPORT entries (acadrust now round-trips
  the render mode via DXF code 281 / DWG RC 281), restored on open for
  both tiled and single-tile model layouts.
- Bump acadrust to pick up the VPORT render-mode field.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 10:32:48 +03:00
Hakan Seven
b0e9270a7e chore(release): bump to 0.4.7
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 00:53:38 +03:00
Hakan Seven
b7230baae1 fix(deps): bump acadrust — keep tiled *Active viewport cameras distinct
Pull acadrust b6834f2, which stops the DWG writer from collapsing every
duplicate *Active viewport to a single zoom-extents view. Fixes tiled
model layouts all sharing one camera after save→reopen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 00:00:28 +03:00
Hakan Seven
f147e384d0 acadrust update 2026-06-01 20:09:31 +03:00
Hakan Seven
7bf9ce31ae feat(model): 3D solid modelling tab — primitives + boolean ops
Rename the Home tab to "Draw" and add a Model tab beside it with two
groups:

- Model: BOX / CYLINDER / CONE / SPHERE / WEDGE / TORUS, placed with a
  footprint + height. Each is built as a real ACIS Solid3D (acadrust
  primitive builders) plus a truck B-rep, tessellated into the shaded
  mesh pipeline, with edge wires for picking + wireframe.
- Design: UNION / SUBTRACT / INTERSECT via truck-shapeops.

A session-only Scene.model_solids cache holds each solid's truck B-rep
so the boolean tools can combine and chain them. Supersedes the old
command-line BOX/SPHERE/CYLINDER (insert::solid3d_cmds keeps EXTRUDE/
REVOLVE/SWEEP/LOFT).

Known limitations: booleans need solids created this session; curved
ACIS primitives render in-session but not after reload (the SAT
tessellator handles only planar caps); geometry assumes world_offset 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 19:27:06 +03:00
Hakan Seven
83d36e02e3 chore(release): bump to 0.4.6
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 14:46:16 +03:00
Hakan Seven
ac9022676f feat(mtext): editable preview with caret, blink, and new-line support
Type directly into the rendered MText preview: click to position the
caret, insert/delete, Enter for a new line, Space for a literal space,
and arrow keys to move. The caret blinks when idle.

Keep the trailing empty paragraph in the editor so the caret appears on a
fresh line immediately after Enter, before any typing. parse_mtext_paragraphs
split into a _ex variant; layout_mtext skips the blank-edge trim when
emitting glyph boxes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 13:14:35 +03:00
Hakan Seven
db6e8873f2 chore: bump version to 0.4.5
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 23:42:42 +03:00
Hakan Seven
0602ae82f8 chore: bump version to 0.4.4
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:17:20 +03:00
Hakan Seven
269e21cbfb release: v0.4.3
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 22:46:05 +03:00
Hakan Seven
ded1b7b158 chore(release): bump to 0.4.2
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 14:19:05 +03:00
Hakan Seven
b2d9660221 chore(release): bump to 0.4.1
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 22:48:30 +03:00
Hakan Seven
05ea31aa2a feat(commandline): autocomplete suggestions + inventory-based registry
Type-as-you-go suggestion popup above the input that filters known
command names by substring (so `LEADER` surfaces both LEADER and
MLEADER). Up / Down navigates the list, Enter dispatches the
highlighted entry, clicking a row dispatches directly. Esc on a
non-empty input clears the buffer instead of escalating to
command-cancel.

The name corpus comes from `inventory::submit!` blocks placed next
to each `CadCommand` impl rather than a hand-maintained static list.
Adding a new interactive command means dropping one `inventory::submit!`
line in its own module file — the autocomplete picks it up at the
next compile. 98 submissions seeded across 60 module files;
`command::all_registered_command_names()` flattens them at runtime.

One-shot dispatch arms in `app/commands.rs` (NEW, OPEN, SAVE, UNDO,
…) don't have a `CadCommand` impl and are therefore absent from
autocomplete by design.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 22:45:54 +03:00