Commit Graph
341 Commits
Author SHA1 Message Date
Cursor Agentandnrq6993-a11y 5359c92a19 G11: Arc segment dialog options wired to shape.arc
Replace length/angle with Length X/Y, reference point, Type, Base Along, Slope and Fill Arc; extend geom and shape.arc params.

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 13:38:04 +07:00
Don Omondi a3b2b18cb0 M3: preserve highlighted Eyedropper ranges and reject incompatible transparency 2026-10-22 02:58:48 +07:00
bflatastic 10a178f64a Shape Builder: Gap Detection and Tool Options (#2523)
Squashed from #2526 onto main.
2026-10-22 02:53:17 +07:00
dotCooCoo 4bd55029e8 Live Paint: the Live Paint tools and livePaint.fill skip hidden faces
A face hidden on its own (for example with Object > Hide after Live
Paint Selection picks it) while its Live Paint group stays visible was
still highlighted, selected by Live Paint Selection and filled by the
Live Paint Bucket, and it kept the face of a group behind it from being
picked.

live_paint_at and lp_part_at now take the front-most face that is not
hidden (visible_face_at). A point on a hidden face falls through to the
visible face of a group behind it; where there is none, an edge pick
takes the nearest visible edge as it does outside the faces.
livePaint.fill also skips hidden faces. With group, a point on a hidden
face is an error. With ids, it fills the face there of another Live
Paint group among the objects, or else fails and does not merge the
group.

Docs: docs/mcp.md.
2026-10-22 02:01:58 +07:00
bflatastic c895f64063 Format: rustfmt after the batch 2026-10-21 23:38:03 +07:00
nrq6993-a11yandCursor ab0ddf0eae G1: Live Corners relative rounding (#1144)
Store corner radii as fractions of each corner's max so rounding scales with the shape; expose via Corners dialog and object.setLiveShape relativeRadii.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:03 +07:00
Cursor Agentandnrq6993-a11y b13072b77c M3: rustfmt eyedropper and brush key-color UI
Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-21 23:38:03 +07:00
nrq6993-a11yandCursor 6433b6ca3a G5: Pattern brush Key Color eyedropper in Brush Options
Hue Shift colorization can sample key color from canvas art via the
eyedropper next to the swatches, matching Illustrator's brush workflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:03 +07:00
bflatastic 58066428c6 Artboards: the Artboards panel locks an artboard and the art on it
Squashed from #2592 onto main.
2026-10-21 23:38:02 +07:00
Jürg Lehni af2618c9e4 Threaded text: type on a path threads, mixed with area type
Illustrator links type in an area or along a path (https://helpx.adobe.com/illustrator/using/manage-text-area.html); until now only area type threaded here. Type on a path that overflows ends its line where its text stops fitting, so a story flows on from it, and its red out port, just past its end bracket, loads the Selection tool with the text as area type's does. A new frame threaded from it at a point is type on a path of its shape.
2026-10-21 23:15:45 +07:00
dotCooCoo a5ea3a8002 Use Preview Bounds: a handle drag keeps the opposite visible edge in place
With Use Preview Bounds on, a bounding-box handle drag scaled the art by
the ratio of the visual box, so margins that stay (a stroke with Scale
Strokes & Effects off, an Offset Path reach) or scale by another factor
moved the opposite visible edge: dragging the right edge of a square with
Offset Path 10 from 210 to 310 left its left edge at 98.33 instead of 90.

The Selection tool now previews object.setBounds with the dragged visual
size and the opposite handle (with Alt, the center) as the reference
point, so the scale is solved from the geometric box and the margins the
visual box adds, for strokes with Scale Strokes & Effects on or off and
for geometry effects. Shift and Alt drags follow the same rule; a drag
that flips the box, and one with anchors selected, still scale by the
matrix. A previewed object.setBounds runs as object.transform with the
transform it finds, so Transform Again repeats the drag and the journal
holds that transform. The drag transforms a path of a compound path
selected on its own, as object.transform does, and leaves the art at
least 1e-4 of its width and height.
2026-10-21 17:11:08 +07:00
dotCooCoo 9f31471042 Use Preview Bounds: the selection tools measure the selection once per revision
With Use Preview Bounds on, every hover frame's cursor and every
pointer move measured the selection again, and with Smart Guides on
each selected object too, evaluating their geometry effects each time.

The session now keeps a PreviewMemo, which ToolContext::preview_memo
passes to the tools. selection_bounds, selection_box and the object
bounds that Smart Guides find centers in while hovering read it. The
memo holds the measurements for one key: the document's uid and
revision, the selected objects and Use Preview Bounds. A new key
replaces them. VectorcraftApp::selection_box in the UI keys on the
uid, the revision and Use Preview Bounds. A ToolContext without a
memo measures on every call.
2026-10-21 17:11:08 +07:00
dotCooCoo 1267efbcf9 Use Preview Bounds: objects are measured with their geometry effects
With Use Preview Bounds on, the bounding box, the Transform panel,
Align, Distribute, Distribute Spacing and object.setBounds measured
each object without its geometry effects. A square with Offset Path
10 measured as the square, and type with Outline Object measured by
its layout box instead of its glyphs.

The new vectorcraft_effects::preview module measures objects as they
are drawn. A path is measured by its effected shape, with the
geometry effects of each fill and stroke that paints. Type, images,
live objects and symbol instances are measured by their reshaped art.
A group or layer with geometry or Pathfinder effects, or with a fill
or stroke of its own that has geometry effects or paints members with
geometry effects, is measured by its evaluated art. A blend, envelope
or repeat whose objects have geometry effects is measured by its
evaluated art, with those objects measured after their effects. Raster
effects are not measured. In one object, the art of at most 4,096 symbol
instances is measured with its geometry effects, and the other
instances are measured without them. With Use Preview Bounds off, the
measures are unchanged.

object.setBounds sizes objects with geometry effects by measuring
them after each scale it tries, so type with Outline Object set to
100 pt wide gets a glyph box 100 pt wide.

Selection::anchors_box is split out of Selection::anchor_bounds. The
doc comment of VectorcraftApp::selection_bounds said that it includes
effects; it now says that it leaves them out.
2026-10-21 17:11:08 +07:00
bflatastic dda52d0b20 Artboards: each artboard can have a background color on the canvas
Squashed from #2403 onto main.
2026-10-21 17:11:08 +07:00
dotCooCoo e5b1f0c191 Shape Builder: double-clicking the tool opens Shape Builder Tool Options
Double-clicking the Shape Builder tool reported that the tool has no
options. The reference app opens Shape Builder Tool Options there.

The dialog sets Consider Open Filled Paths as Closed, Pick Color From
(Artwork or Color Swatches), Cursor Swatch Preview, Selection (Freeform
or Straight Line) and Highlight Fill. The defaults keep today's
behavior. With Consider Open Filled Paths as Closed off, a filled open
path cuts regions as an unfilled one does. With Color Swatches, a merge
fills the new shape with the current fill, and the Left and Right arrow
keys step the current fill through the document's color swatches.
Cursor Swatch Preview shows the current fill and the swatches before
and after it above the pointer. With Straight Line, a drag merges what
the line from its first point to its last crosses. With Highlight Fill
off, merge mode shades no regions.

The options persist like other tools' options. shapeBuilder.merge
takes openFilledAsClosed and pickColorFrom, and shapeBuilder.regions
takes openFilledAsClosed. Gap Detection, "In Merge Mode, Clicking
Stroke Splits the Path" and Highlight Stroke When Editable are not part
of this change.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-21 17:11:07 +07:00
dotCooCoo 1047c82bd3 Artboard tool: Shift-drag draws an artboard inside another or marquee-selects artboards
With the Artboard tool, a Shift-press on an artboard toggled it in the
selection and started a move, which Shift kept at 45° steps. A
Shift-drag on the pasteboard drew a square artboard. The reference
app's documentation gives Shift-drag inside an artboard as the way to
draw an artboard there, and Shift-drag on the canvas as a marquee that
selects artboards.

A Shift-click now toggles its artboard when the button comes up. A
Shift-drag inside an artboard draws a new artboard (artboard.new), and
a Shift-drag on the pasteboard toggles every artboard it touches, the
last one added becoming active. Shift no longer constrains an artboard
move or keeps a new artboard square, and no other modifier does. Shift
on the active artboard's handles still resizes it proportionally. The
hint bar names the Shift gestures in every complete catalog, and the
cursor is a crosshair over an artboard while Shift is held.

Escape while a new artboard was being drawn left the tool. Escape
during any drag, the new marquee included, now cancels the drag and
keeps the Artboard tool, as it already did during a move or a resize.

Docs: docs/target-app-parity.md.
2026-10-21 16:55:17 +07:00
dotCooCoo f761ae2585 Pencil and Paintbrush: holding Alt shows the closing loop cursor
Holding Alt while drawing with the Paintbrush, or with the Pencil while
Alt key toggles to Smooth Tool is off, closes the path at the release,
but the cursor did not change. The reference app's Paintbrush shows a
small loop while Alt is held, and its Pencil shows a small circle.

Cursor::PaintbrushClose and Cursor::PencilClose show while Alt is held
with the Paintbrush, and with the Pencil while that option is off,
before the press and while drawing. Both tools still borrow the
crosshair, so the closing cursors are drawn as that crosshair with the
PenClose ring. Use Precise Cursors turns them into the plain crosshair,
as it does PenClose.

With Alt key toggles to Smooth Tool on, the Pencil shows the Smooth
cursor while Alt would smooth: with Alt held before a stroke begins to
draw, and through a smoothing drag even after Alt is let go. Before, it
showed the Smooth cursor whenever Alt was held, also during a stroke
that kept drawing, and not during a smoothing drag once Alt was let go.

Docs: docs/target-app-parity.md, crates/tools/src/cursors.toml.
2026-10-21 16:55:17 +07:00
dotCooCoo 6a1c8eda46 Part of #1816: Snap to Grid lands a moved object by its nearest edge and no longer snaps its center
With View › Snap to Grid on, a whole object moved with the Selection,
Group Selection or Direct Selection tool landed on the grid by
whichever of its two edges or its center was nearest a gridline on
each axis. An object on the grid whose width is an odd number of grid
steps has its center half a step between gridlines, so a short drag
could pull it half a step off the grid: on a 20 pt grid, a 100 pt
square at (100, 100) dragged by (8, 8) moved by (10, 10).

A move now lands the nearer of the two edges on a gridline on each
axis, as the reference app's help describes, and the center no longer
snaps. The square above stays at (100, 100). This changes the rule #769
chose for #740. The plain move and the Shift-constrained one both use
grid_pull, so both change.

Docs: docs/target-app-parity.md (Drawing aids).
2026-10-21 16:55:17 +07:00
dotCooCoo 84833d10ce Blob Brush: Shift keeps the stroke horizontal or vertical
A Blob Brush stroke followed the pointer whatever modifier keys were
held. The reference app's shortcut list has Shift constrain the Blob
Brush path horizontally or vertically.

With Shift held during a drag, each point of a Blob Brush stroke now
goes on the horizontal or vertical line through the press point that
is nearer in angle to the pointer, at 90-degree steps from the
Constrain Angle preference, and keeps its distance from the press
point. When the pointer crosses to the other line, the points dragged
since Shift went down move to it, each on its own side of the press
point. Each point reads the Shift state of its own event, so the
points dragged while Shift is up follow the pointer. The stroke still
runs path.blob once on release.

Docs: docs/target-app-parity.md.
2026-10-21 16:46:40 +07:00
MarekSpodBiedry cde39698ff Draw from centre (Alt) now applies to the typed size of a rectangle or ellipse (#3309) 2026-10-21 16:46:38 +07:00
dotCooCoo 6041bb3c62 Objects on Path: clipping paths and parts of blends, envelopes and repeats stay in place
object.objectsOnPath.attach took a path inside a compound path, blend,
envelope, repeat or Intertwine group, or a clipping path, as the path
and put it into the new Objects on Path group, so it was no longer a
part of its container. As objects, a blend's key path, a repeat's
source art, an envelope's content and a clipping path were put into
the new group the same way.
The Objects on Path tool highlighted a blend's key path or a clipping
path and attached the selection to it.

objects_on_path::held now finds the container that holds an object.
The command refuses such a path or object with a reason, and the tool
does not highlight it or attach to it. A member of a compound path
given as an object still attaches as its whole compound path. The four
new messages have rows in every complete-message catalog.

Docs: docs/mcp.md (Objects on Path).
2026-10-21 16:46:13 +07:00
dotCooCoo 0ec23d90bc Live Paint: the Live Paint tools skip hidden edges
An edge hidden on its own (for example with Object > Hide) while its
Live Paint group stays visible could still be highlighted, selected or
stroked, and a hidden edge nearer the pointer kept a visible one from
being picked.

lp_part_at now takes the nearest visible edge (visible_edge_near), inside
and outside the faces, for the hover, the Live Paint Selection click and
the Bucket's Shift-click. The Bucket's Shift-click sends nothing where no
edge is highlighted, and livePaint.strokeEdge also skips hidden edges, so
the Bucket strokes the edge it highlights.
2026-10-21 16:46:11 +07:00
dotCooCoo ed93963d73 Live Paint: a Live Paint Selection click outside the faces selects the edge it highlights
With Select Fills off, or with Alt held, the Live Paint Selection tool
highlighted an edge near the pointer even when the pointer was outside
every face, but a click there looked only for a face under the pointer
and cleared the selection. Outside the faces, the highlight came from
the front-most Live Paint group with an edge in reach, not from the
nearest edge, and it included hidden groups. The Live Paint Bucket's
Shift highlight and Shift-click used the same search.

The hover, the Live Paint Selection click and the Bucket's Shift-click
now call one function. Outside every face it picks the edge nearest
the pointer, within 4 screen pixels, among the visible Live Paint
groups. A click selects or strokes the edge that the highlight shows.

This change follows up #3052.
2026-10-21 16:46:11 +07:00
Drew DibbleandClaude Opus 5.5 5fd553cc8b G1: loaded text, double-clicks and guide release take what is drawn
The selection tools' clipping-path outline hit was also used where the
Selection and Direct Selection tools act on what is drawn rather than
select. Near a layer's clipping mask edge, with art drawn over it:
loaded text threaded into the unpainted mask instead of the art, a
double-click on type entered isolation on the mask instead of editing
the type (Selection) or did nothing (Direct Selection), and Cmd/Ctrl+
Shift double-click could not release a guide path there. These now
take the ordinary hit (ToolContext::hit_options); a press or hover
that selects keeps the outline hit.

Tests (each fails with the selection hit options):
select::tests::loaded_text_threads_into_the_art_on_a_layer_masks_edge,
a_double_click_on_type_at_a_layer_masks_edge_edits_it (Selection and
Direct Selection) and a_guide_on_a_layer_masks_edge_is_released, over
the new testutil helpers add_masked_layer and
doc_with_type_on_a_layer_masks_edge. Recorded in
docs/target-app-parity.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 15:44:27 +07:00
Drew DibbleandClaude Opus 5.5 061e905724 G1: selection tools take a clipping path on its outline
A clip group answered a press only strictly inside its clipping path,
and there the art above the path came first in the hit test, so where
the clipped art extends past the mask's edge the clipping path's
segments could not be reached on the canvas.

With the new HitOptions::clip_outlines, which the Selection, Direct
Selection and Group Selection tools set
(ToolContext::selection_hit_options), a press within the selection
tolerance of a clipping path's outline, inside or just outside it,
hits the clipping path (HitKind::Outline) before the art it clips:
Direct Selection takes its segments and the Selection tool the clip
group. It applies to a clip group's clipping path and to a layer's
clipping mask, and only to one a click may hit (may_hit: visible,
editable, within reach). Inside the mask the art is hit as before.

The other tools, which act on what is drawn (the eyedropper, type,
gradients...), leave the option off, and hit_test_visible never
applies it, so they still take the art at the mask's edge rather
than the mask's empty appearance. Select Behind's one-pass walk takes
a layer mask's outline first too, so it lists what the repeated hit
test finds. Object Highlighting and a right-click's selection in the
canvas (selection_hit_at) take what those tools take; dropping a
swatch on art still hits what is drawn.

The reference app reshapes a clipping path with Direct Selection:
https://helpx.adobe.com/illustrator/desktop/manage-objects/edit-objects/edit-clipping-masks.html

Tests in doc: a_clipping_path_is_hit_on_its_outline_before_its_art,
only_the_selection_tools_hit_a_clipping_path_on_its_outline and
select_behind_takes_a_layer_masks_outline_first; the random Select
Behind test now clips layers and sublayers and sets clip_outlines,
and fails without the Select Behind change. In tools,
a_press_on_a_clipping_path_takes_its_segment_over_the_art fails
without the change; select::a_press_on_a_masks_edge_selects_its_clip_group
fails when the Selection tool uses the plain options; the eyedropper
copies the art on the edge. Recorded in docs/ui-parity.md,
docs/gaps.md and docs/target-app-parity.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 15:42:37 +07:00
dotCooCoo ba8c1e042c Pencil: Edit selected paths within 0 turns editing off
docs/control-protocol.md and the tool.options params text say that 0
turns the Pencil and Paintbrush options Edit selected paths within and
Close paths when ends are within off. A stroke that
started exactly on an end of a selected open path still continued that
path at 0, and a stroke that ended exactly where it started was still
closed at 0, because both checks compared the distance with <= 0.

At 0, a stroke that starts on an end of a selected open path now draws
a new path, as one that starts on the path away from its ends already
did, and a stroke that ends where it started stays open.

Docs: docs/target-app-parity.md.
2026-10-21 15:42:37 +07:00
nrq6993-a11yandCursor 5ebef8282a G1: Anchor Point Shift-drag shows move distance in measurement labels
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 15:42:36 +07:00
nrq6993-a11yandCursor 87686e81f2 G1: Reshape tool shows offset readouts while dragging paths
Honor Show Measurement Labels with dX/dY labels during reshape previews.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 15:42:36 +07:00
nrq6993-a11yandCursor 32834a9135 G1: Place drag test disables measurement labels for marquee-only overlay check.
testutil: :cx defaults measurement_labels on, so the aspect-ratio drag assertion must not expect a lone Marquee overlay.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 15:42:36 +07:00
nrq6993-a11yandCursor 2927ff6e85 G1: Place tool shows placement size in measurement labels while dragging.
Honor Show Measurement Labels on the file Place cursor so sizing drags get W/H readouts like other draw tools.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 15:42:36 +07:00
nrq6993-a11yandCursor e76a9c1a45 G1: Area type drag shows W/H in measurement labels
Honor Smart Guides › Measurement Labels while drawing an area-type frame with the Type tool.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 15:42:35 +07:00
NetterSilverandClaude Haiku 5.5 89c1448777 Normalise negative zero in Measure tool angle
Found while testing crates/tools/src/xform/measure.rs:20 (shown at :66, reported at :80)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 15:20:12 +07:00
nrq6993-a11yandCursor e2e2ac12a9 Group Selection: fold MoveObject pointer-up into shared arm
Read deselect before idle reset and handle shift-deselect via select.toggle in the shared Up match.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 07:00:49 +07:00
nrq6993-a11yandCursor 61f35cd037 G1: Group Selection Shift-click deselects compound path members
Match the Selection tool: Shift on an already selected hit removes it on
release without a drag, including one path of a compound path.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 07:00:49 +07:00
Dan Green 7852f363a1 Fix #2143: selected ruler guides align to a key object
A lone object selected with ruler guides can be the key (the Selection
tool's click on it), and Align to the key moves the other selected
guides to its edge or centre: vertical guides to left, centre or right,
horizontal ones to top, centre or bottom. Parallel guides line up on a
key guide. Aligning to the selection or the artboard leaves guides alone.
2026-10-20 05:56:59 +07:00
Dan Green 263c36567f Fix #2143: a ruler guide can be the key object Align lines objects up on
A click with the Selection tool on a guide selected with objects makes
it the key (select.key {guide}), drawn thicker; a click on it again
cancels it. Align to Key Object is on with one object and a selected
guide and makes the guide the key. object.align lines the objects (or
selected anchors) up on the guide's line and leaves the guide where it
is: a vertical guide sets x only, a horizontal one y. The selection
keeps key_guide beside key, never both; it goes with the guide or the
objects, and follows the guide when earlier guides are deleted.
Distribute Spacing doesn't space from a key guide.
2026-10-20 05:56:58 +07:00
bflatastic 92c1657334 i18n: Chalk & Charcoal, Graphic Pen, Reticulation and Plastic Wrap in every catalog that has the Sketch filters (#2972, #2967, #2976, #3034)
Also cargo fmt over the four filters.
2026-10-20 03:14:27 +07:00
nrq6993-a11yandCursor cfea906681 G1: Mesh point drags show dX/dY in measurement labels
Honor Measurement Labels while moving gradient-mesh and mesh-envelope
points with the Mesh tool or Direct Selection.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:48:08 +07:00
nrq6993-a11yandCursor 361ebd29bf G1: Free Distort corner drags show dX/dY measurement labels
Honor Measurement Labels during envelope-style corner drags on the Free Transform tool, matching the Move handle readout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:37:03 +07:00
bflatastic 85163a7c82 Tests: the Snap to Glyph test says what it checks (#3124) 2026-10-20 02:23:34 +07:00
bflatastic 88a444ef7b fmt (#3124) 2026-10-20 02:23:34 +07:00
nrq6993-a11yandCursor 0c62d9c02c G4: View › Snap to Glyph snaps new type to live-text guides
Wire the View menu toggle and add glyph baselines and bounds to drawing snap targets so point type placement lines up with existing text when Smart Guides are on.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:34 +07:00
bflatastic cb229ac08c fmt (#3121) 2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 88bd9bcd9e G4: Touch Type drag test treats omitted zero dx as no kerning
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 222ec72e28 G4: Touch Type arrow keys nudge the selected character
Keyboard increment (Shift ×10) moves the active glyph through text.touchType, with vertical type remapping like the Type tool.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
bflatastic b8f9c403a7 Measure: with Measurement Labels off the measured line still draws, only its readout goes (#3128) 2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 6ef9f2dd93 G1: Measure tool honors Measurement Labels preference
Hide the preview line and readout when Smart Guides › Measurement Labels is off; options still report the last drag.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor fd53416de3 G1: honor Show Measurement Labels on pie, corners, width, and tiling readouts
Tools that showed distance or angle overlays during drags now respect the
Units preference, consistent with shape and selection tools.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
bflatastic d507a73d09 fmt (#3114) 2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 6d713de980 G1: Crop Image honors Smart Guides measurement labels.
Gate the crop size readout on the preference and show it at the pointer while dragging the box.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00