Commit Graph
99 Commits
Author SHA1 Message Date
Hakan SevenandClaude Fable 5.1 75e7f825cd docs(automation): make native.md match the code
The page merged from #1401 described --serve and --mcp as one surface.
Rewritten against src/app/automation.rs, src/app/control/mod.rs and
src/mcp.rs: the --serve readiness banner and --port mode, the two request
styles on that channel and how each treats a waiting command
(command_busy versus replacement), measure being available headlessly
while capture is not, --export writing DWG for every extension but .dxf,
startup dialogs belonging to the editor behind --mcp only, MCP sessions
being shared rather than one editor per connection, the MTEXT editor's
own actions, and the legacy run reply fields (blocked_by, unconsumed)
that only that path returns.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 20:30:46 +03:00
Hakan Seven dece694478 Merge pull request #1401 from buyun14/docs/automation-native-builds
docs(automation): document the native entry points and their limits
2026-09-20 20:28:14 +03:00
Hakan Seven 97b471949c Merge pull request #1394 from helenkwok/docs/automation-web-build
docs(automation): document driving the web build
2026-09-20 20:14:10 +03:00
buyun14 747245a75f docs(automation): document the native entry points and their limits
Refs #1349. The automation README describes `--mcp` and never mentions
`--serve`, even though every native build accepts it and it is the only channel
that works without a display. It also leaves out the two startup dialogs, the
`document_id` routing, and what `waiting_input` actually means.

`docs/automation/native.md` covers, all measured on a Linux headless machine
with `OpenCADStudio 2026.37+165`:

- choosing between `--mcp` and `--serve`, and what each needs (display,
  no-display, `--export` for one-shot conversion);
- the writable `HOME`/`XDG_CONFIG_HOME` requirement, without which
  `ocs_sessions` answers `No user configuration directory`;
- the startup dialogs: `AssocPrompt` then `DonationPrompt`, `new` answering
  `ok` with no document until `close_modal` clears them, and that the donation
  prompt appears once per application version per profile;
- targeting a document: reads and writes follow the active tab, so
  `document_id` has to be passed explicitly after `new`;
- feeding a whole line: `waiting_input` means more input is required (not that
  nothing happened), `cancel` closes a command, and the `unconsumed` /
  `blocked_by` fields added in #1392;
- the interactive `start`/`input` shapes, including that a typed value goes
  through `kind: "text"` while a keyword uses `kind: "token"` with its payload
  in a field named `text`, and that the `TEXT` content step belongs to the
  in-place editor (`text_input` / `text_commit`);
- what only native builds have: `measure`, `ocs_capture` (inline base64, or a
  PNG path), and `set_properties` with `collection` and colours as
  `{"Index": n}` / `"ByLayer"`;
- the remaining gap: `MTEXT`, `HATCH` and `POLYGON` report `completed` with
  `added: 0` on the `--serve` path (#1390).

The README gains one line pointing to the page, placed after the tool list
rather than at the end, so it does not overlap #1394.

Docs only; no code changes.
2026-09-20 19:21:49 +08:00
buyun14 899af80c2f fix(automation): consume and report the tail of a batch command line
`run_command_line` feeds the tokens after the command verb to the interactive
command and then terminates it as if Enter were pressed. Two gaps left a
headless caller unable to tell what actually happened.

In-place text editor takes over, remaining tokens were dropped
----------------------------------------------------------------
The `TEXT` content step hands over to the in-place editor, at which point the
command has already ended (`active_cmd` is `None`). The feed loop stopped
there, so the rest of the line — including the text itself — vanished:
`TEXT 0,0 5 0 hello` reported `completed` with `added: 0` and created nothing.
The tail is now typed into that editor and committed, and the commit is done
synchronously so its result is observable: `text_inline_commit()` returning
false leaves the tokens in `unconsumed` instead of reporting a successful line.
Dispatch the commit as a queued message instead and a failed commit would look
exactly like a good one — the text dropped, `added: 0`, `unconsumed: []`.

Only an editor this line opens is taken over, and after a successful commit the
line is closed with an escape: `TEXT` re-arms for the next line
(`open_next_line`), which would otherwise let the *next* batch line be eaten as
the next text position.

Leftover tokens are dropped
---------------------------
Any token no prompt ever asked for is recorded in `CommandLine::unconsumed` and
surfaced by the automation `run` response, so over-typed or misplaced input is
visible instead of silently ignored: `CIRCLE 0,0 5 9` reports
`"unconsumed": ["9"]` while a fully consumed line reports an empty list.

Pending surfaces are reported instead of `completed`
----------------------------------------------------
`run` now carries `blocked_by` — `"command"`, `"text_editor"`,
`"mtext_editor"`, `"modal:<Kind>"`, or `null` — and answers `waiting_input`
when something is still open rather than claiming `completed`.

`blocked_by` is attributed to the line that opened the surface: a condition and
its snapshot are taken before the command runs, so an editor left open by an
earlier line, another tab, or a startup dialog does not turn a finished command
into `waiting_input`. Without that attribution a caller polling for `completed`
would wait forever on someone else's editor. `docs/automation` documented
`waiting_input` as "more input is required", which is exactly what a pending
surface is; the two new fields are documented there as well.

Tests
-----
* `batch_text_line_creates_text_and_consumes_every_token` — the regression case
  creates exactly one `Text` entity and leaves nothing unconsumed.
* `multi_word_text_keeps_the_spaces` — asserts the committed string, so an
  off-by-one in the consumed index or a wrong join cannot pass.
* `run_reports_leftover_tokens_instead_of_dropping_them`.
* `text_without_content_reports_the_open_editor`.
* `a_stray_editor_is_not_hijacked_by_the_next_line` — the next line neither
  types into the stray editor nor inherits its blocker (`blocked_by: null`,
  `status: completed`).
* `a_command_still_waiting_is_named_as_the_blocker`.

Verified over the `--serve` protocol: `TEXT 0,0 5 0 hello world` → `completed`,
`added: 1`, and the entity really holds `hello world`; `TEXT 40,0 5 0` →
`waiting_input` + `blocked_by: "text_editor"`; the following `CIRCLE 0,0 5 9` →
`completed`, `blocked_by: null`, `unconsumed: ["9"]`; `LINE` → `waiting_input`
+ `blocked_by: "command"`.

Full lib suite: 1497 passed, 2 failed — both failures
(`io::plot_style::…named_tables_and_missing_files_get_a_reason`,
`scene::parametric_constraints::…arc_grips_drive_center_start_and_end_but_not_midpoint`)
reproduce on the unmodified tree; run with `LC_ALL=C` since several xref tests
otherwise fail on a non-English locale.

Known remaining gap, unchanged here: `MTEXT` / `HATCH` still answer `completed`
with `added: 0` in this path (they need interactive surfaces the feeder has no
tokens to fill). Reported separately in #1390.
2026-09-20 19:15:55 +08:00
Helen Kwok 2e871c2c6c docs(automation): document driving the web build
Describe the two JavaScript functions the web build exposes
(ocs_control_submit / ocs_control_take), how to poll them, the queue and reply
limits, opening a drawing from bytes with data_base64, and closing the startup
dialog before new. Everything is taken from src/app/control/mod.rs,
src/app/startup.rs and docs/automation/web_save_smoke.cjs.
2026-09-20 12:50:39 +09:30
Christopher Overbeck 77b793b250 docs(dimension): screenshots for arrow fit, outside text, and radial leader rules 2026-09-17 09:45:13 -05:00
Christopher Overbeck 5b06b6f3fb docs(dimension): before and after screenshots for regenerated dimension layout 2026-09-17 09:32:54 -05:00
Hakan Seven a27545c379 fix: resolve review regressions and align dependencies 2026-09-17 07:47:15 +03:00
Hakan Seven 45d9ce9782 Merge pull request #1321 from ghost/dimlim-nominal-replacement 2026-09-17 07:12:53 +03:00
Hakan Seven 79bc800728 Merge pull request #1320 from ghost/styled-dimension-preview 2026-09-17 07:11:10 +03:00
Hakan Seven 0c9cb72069 Merge pull request #1316 from ghost/hide-dynamic-dimension-placement 2026-09-17 07:09:06 +03:00
Hakan Seven 49afac176b Merge pull request #1306 from ghost/plugin-doc-findings 2026-09-17 06:50:21 +03:00
Christopher Overbeck 1474376924 docs(dimension): before and after screenshots for DIMLIM limits stack 2026-09-16 17:29:32 -05:00
Christopher Overbeck 7cd5aefc17 docs(dimension): add placement preview screenshots
Before and after captures of DIMLINEAR at the second-point and placement
stages and DIMANGULAR at arc placement, taken from the upstream base and
this branch with the same automation steps.
2026-09-16 13:58:44 -05:00
Christopher Overbeck 3196d185a1 Add dimension placement before and after screenshots 2026-09-16 10:40:35 -05:00
Hakan Seven d10a0cf798 Merge pull request #1301: Add associative viewport dimensions
Refresh associations after complete SpaceMouse camera updates and recognize imported paper-space owners without Layout objects. Use kernel containment, intersection, perpendicular and spline tangent solving; pin cadkernel 7ce27f2 and add regressions.
2026-09-16 09:56:33 +03:00
Hakan Seven af847ad92e Merge pull request #1299: Add Windows SpaceMouse navigation 2026-09-16 09:41:25 +03:00
Felix RiestraandClaude Sonnet 5 bd49bd66d4 docs(plugin): fix inaccuracies and flag real gaps found building a plugin
Found while building an out-of-tree scripting plugin from scratch against
this doc and the actual ocs_plugin_api/host source. Two categories:

Fixed outright (docs/examples didn't match the real code):
- The worked CadModule example returned Vec<RibbonGroup> from
  ribbon_groups(); the real trait requires &[RibbonGroup] - the example
  wouldn't compile. Fixed with the OnceLock pattern the host's own
  benchmark code already uses.
- Reconciled a contradiction between "process isolation removes the need
  for a shared Rust ABI" and the exact-rustc_version requirement described
  a few paragraphs earlier in the same doc.
- The roadmap's "Next" list still had external automation as unstarted;
  --mcp/--serve are real and operational (src/cli.rs, src/mcp.rs).
- Added the missing plugin.toml to docs/plugin-template-v2 (its own
  DESIGN.md already claimed one could be installed).
- Documented that plugin-template's CI floats rust-toolchain@stable, which
  doesn't guarantee matching the host's exact rustc - added acadrust_source
  to both templates' plugin.toml plus the release.yml step that fills it
  from Cargo.lock's resolved acadrust source, alongside the existing
  rustc_version fill.

Flagging for your call, not fixed here (found the behavior, not sure it's
the intended one, prefer to ask than guess at a fix):
- acadrust_compatible()'s ABI gate only runs at all if plugin.toml declares
  acadrust_source - an undeclared field is silently treated as compatible,
  unlike rustc_version (undeclared = incompatible). The same shortcut
  appears in two places: ExternalPlugin::acadrust_compatible
  (src/plugin/external.rs) and the inline check inside fetch_release_info
  (src/plugin/marketplace.rs). If this is deliberate (e.g. back-compat with
  manifests from before the field existed), no action needed beyond a
  comment; if not, both call sites need the same fix.
- The command line still uppercases typed/pasted input even with the `>`
  literal-spaces prefix (Message::CommandInput, src/app/update/mod.rs) -
  `>` only stops a space from auto-submitting the line, it doesn't skip
  `s.to_uppercase()`. A plugin command needing a case-sensitive typed
  argument has no escape today short of automation.
- fetch_release_info (src/plugin/marketplace.rs) returns every release
  under a linked repo with no filter on the manifest's own id field (which
  it already parses to build ReleaseInfo) - a repo hosting more than one
  plugin under tag-namespaced releases surfaces all of them mixed
  together in one plugin's version list.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 03:37:54 +02:00
Christopher Overbeck 5424a19482 Track mixed paper and viewport dimension references 2026-09-15 16:00:11 -05:00
Christopher Overbeck 6ed9714c6a Integrate final viewport creation branch and retain association regression coverage 2026-09-15 14:54:17 -05:00
Christopher Overbeck 64ce0b2e8c Resolve viewport dimension features and preserve valid measurements on refresh 2026-09-15 14:53:45 -05:00
Christopher Overbeck 3274d6d0fd Validate viewport object picks and cover angular arc acquisition 2026-09-15 14:53:29 -05:00
Christopher Overbeck 2ee3782850 Fix viewport dimension acquisition and preserve measurement scaling 2026-09-15 14:13:19 -05:00
Christopher Overbeck 6a63726eff Add Windows SpaceMouse navigation through 3DxWare 2026-09-15 13:20:19 -05:00
Christopher Overbeck e52e565b1f fix(renderer): keep draw-order offsets within clipping planes 2026-09-15 12:36:05 -05:00
Hakan Seven d738ebfcc6 Standardize parametric constraints and interoperability 2026-09-15 03:19:52 +03:00
Hakan Seven 753df67ee4 Complete parametric drawing interoperability 2026-09-14 23:51:37 +03:00
Hakan Seven 912b217d26 fix: delegate dimension transforms to cadcodec 2026-09-14 14:22:10 +03:00
Hakan Seven 010d23fa95 chore: sync reviewed dependency mains 2026-09-14 10:02:49 +03:00
Hakan Seven 2f741d689f fix: address open PR review findings 2026-09-14 09:45:37 +03:00
Hakan Seven fc1788df65 fix: export interoperable DWG constraint graphs 2026-09-14 02:57:33 +03:00
Hakan Seven 95bad2a3b2 Fix web folder paths and allow main-only web hotfix deployment 2026-09-13 20:30:12 +03:00
Hakan Seven 07acd1284c Render procedural checker materials correctly 2026-09-13 01:50:42 +03:00
PanosandClaude Opus 5 5f161bb037 Show the exact build in About, Copy Info, REPORT and --version
Builds from main reported only the release version (2026.36) even when
HEAD was hundreds of commits past the tag. build.rs now also emits
OCS_TAG_DISTANCE, OCS_COMMIT_DATE, OCS_BUILD_METADATA and
OCS_FULL_VERSION: a clean checkout of the release tag stays "2026.36",
anything else becomes "2026.36+194.gef189d77", with ".dirty" appended
for uncommitted changes and only the hash when no tag can be counted
from (shallow clone, tarball). OCS_APP_VERSION is unchanged so the
update check, donation gate, User-Agents and window title keep working.

The About dialog gains Build / Commit date / Profile cards, Copy Info,
the REPORT issue template and recovery reports carry the full version,
and `-V`/`--version` print it instead of Cargo's 2026.36.0. Release
workflows check out full history so release binaries see the tag.

Also fixes the build being marked dirty when there is no repository:
diff-index exits 128 there, not 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 16:19:40 +03:00
Hakan Seven 932bf970c6 Update CAD dependencies 2026-09-12 14:13:49 +03:00
Hakan Seven ef189d7781 Update CAD dependencies for DWG template fix 2026-09-11 21:42:29 +03:00
Hakan Seven 798379fbe0 Update dependencies after cadcodec PR 44 2026-09-11 19:13:22 +03:00
Hakan Seven 5e91e23752 Update codec and kernel dependencies 2026-09-11 18:52:31 +03:00
Hakan Seven 9b58ca8a93 Harden parametric sketch constraints 2026-09-11 09:45:57 +03:00
Felix RiestraandClaude Sonnet 5 cf33a1d019 Add DWG/DXF-native constraint persistence alongside the XRecord format
Implements docs/dwg_constraint_compatibility_design.md's staged plan in
full: materializes the sketch-constraint set as acadrust's real
AssocNetwork/Assoc2dConstraintGroup object graph on save, additive to
the existing OCS_SKETCH_CONSTRAINTS XRecord, so files also carry
constraints AutoCAD/BricsCAD recognize as their own native objects
(per Hakan's request on the upstream project). Covers every
ConstraintKind, including AssocVariable wiring for named-parameter
driving values, and clears+rebuilds on each save.

DWG round-trips the full dependency chain; DXF only keeps the
constraint-group shell since acadrust's own DXF writer deliberately
omits AssocDependency-family objects. Both behaviors are covered by
tests and documented in the design doc's progress section, along with
two other implementation-time findings (skipping the NOD-anchored
top-level network, and the DWG writer's root-node/connections wire
format).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 17:26:53 +02:00
Felix RiestraandClaude Sonnet 5 5d93476c01 Add DWG-native constraint compatibility design doc
Hakan (upstream maintainer) asked for the sketch-constraint system to
persist using the constraint object model already exposed in acadrust/
cadcodec (Assoc2dConstraintGroup, AssocConstraintNode), so a file saved
by OpenCADStudio carries constraints AutoCAD/BricsCAD recognize as
their own native objects, not just an opaque custom XRecord blob.

Covers:
- The full ConstraintKind -> AssocConstraintNodeData mapping table,
  grounded in build_constraint's actual refs shapes (the real contract,
  not the doc comments).
- The geometry-node mapping for SketchRef (line/circle/arc/point
  references) onto Line/BoundedLine/Circle/Arc/ImplicitPoint nodes.
- The AssocNetwork -> AssocAction -> Assoc2dConstraintGroup graph shape
  actually needed, not just a flat data swap.
- A proposed additive persistence strategy: write both our own
  OCS_SKETCH_CONSTRAINTS XRecord and the native graph, since our model
  carries things (DrivingValue::Named) the native graph can't yet
  losslessly express.
- Known gaps: Equal has no length/radius sub-kind split natively,
  several AutoCAD constraint types we don't model at all, Tangent
  involving an Arc (a pre-existing gap in the constraint system,
  unrelated to DWG compatibility).

Three of five open questions are resolved against Autodesk's own
primary sources rather than left as inference: the ObjectARX 2012 SDK's
own C++ headers (mirrored on GitHub, Autodesk's own copyright notice
grants free use/distribution -- it's the SDK Autodesk publishes for
third-party interop) and Autodesk's live public ObjectARX reference
site. Confirmed: the associative network's dictionary key
("ACAD_ASSOCNETWORK"), the AcDb::ImplicitPointType enum settling how
SketchRef's point markers map to constraint geometry nodes, and that
AssocVariable's evaluator field can be left empty (Autodesk's own doc:
"the default evaluator for current acad version will be used"). Two
questions remain and need a real write-then-open test rather than more
reading: whether AutoCAD tolerates a partially-populated graph, and
DWG version gating on fields not yet checked.

Suggested staged approach: prove out Horizontal/Vertical on a single
Line first (sidesteps the value-dependency wiring), verify it opens
cleanly in real AutoCAD/BricsCAD or a DWG inspector, before writing
more of the graph on an unverified foundation. Design only -- no
implementation yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 14:48:02 +02:00
Felix RiestraandClaude Sonnet 5 7cddf31bcb Add named parameters, UI scale setting, OPTIONS/OP dispatch, and help manual
Named parameters (docs/named_parameters_design.md, stages 3-4):
- ParameterTable (src/scene/named_parameters.rs): a document-wide table of
  named formulas, each resolved through a shared expression evaluator with
  cross-parameter references, cycle detection, and division-by-zero/parse
  error reporting. SketchConstraint::driving_param becomes DrivingValue
  (Literal | Named) instead of a bare f64, resolved at solve time by
  sketch_solve::build_constraint via Scene::named_parameters.
- Persistence (src/scene/named_parameters_persist.rs): same lazy XRecord
  model sketch_persist.rs already established, synced around open/save.
  Bumps the sketch-constraint XRecord's own format version (1 -> 2) since
  DrivingValue's shape doesn't line up with a version-1 blob's bytes.
- PARAMETERS command and its editor (src/ui/window/named_parameters.rs):
  add/remove/edit rows, live validation, duplicate-name detection: Apply
  defines the table and re-solves every constraint scope with a
  named-parameter-driven constraint (command_driver.rs). Distance/Angle
  constraint prompts (modules/draw/constrain/value.rs) now accept either a
  literal or an existing parameter's name, mirroring how the constraint's
  own value prompt already worked.
- Undo scope-down carried over from this project's own established pattern
  (constraint-system stage 9): the geometry an Apply moves is one undo
  step, but the parameter table edit itself has no undo entry yet — a
  documented follow-up, not a silent gap.

UI scale setting (src/app/settings.rs, app/mod.rs, ui/window/options.rs):
  a whole-interface scale percentage (50-200%), wired directly into iced's
  own per-window scale_factor hook rather than per-panel font-size
  plumbing, so it applies immediately to every panel, dialog, and the
  ribbon at once. Persisted alongside the existing lineweight-display-scale
  setting.

OPTIONS/OP command dispatch (app/commands/view.rs, app/commands/mod.rs):
  OPTIONS was registered for autocomplete but had no dispatch arm — the
  Start-tab welcome screen's own button was the only way to reach it.
  Found live-testing the UI-scale setting, unrelated to that feature
  itself. "OP" is AutoCAD's own short alias.

help/: a new self-contained static user-help manual (manual.md as the
authored source, tools/build_help.py splits it into the committed static
HTML pages plus search index) — not yet wired into the application.

64 new/updated tests across the named-parameters and constraint-prompt
changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 13:50:08 +02:00
Felix Riestra e2d39b049d Merge branch 'main' into feature/parametric-constraint-system
# Conflicts:
#	src/app/automation.rs
#	src/app/mod.rs
#	src/ui/ribbon/widgets.rs
2026-09-09 13:35:07 +02:00
Hakan Seven 4ddd19f6e8 feat(mcp): describe complete CAD record schemas 2026-09-09 01:01:44 +03:00
Hakan Seven 8f574c8388 feat(mcp): expose complete drawing records 2026-09-08 23:59:13 +03:00
Felix RiestraandClaude Sonnet 5 63a74b19a9 Add persistent sketch-constraint system (ocs_gcs port) and named-parameters handoff docs
Ports FreeCAD's planegcs 2D geometric constraint solver to Rust as a new
crates/ocs_gcs workspace member, and wires it into the document/scene model
as a persistent SketchConstraintSet: Coincident, Horizontal/Vertical,
Parallel/Perpendicular, Equal, Tangent, Distance, Angle and Radius
constraints that re-solve live (including mid-drag, not just on release),
render glyphs and a DOF badge, flag conflicts with a one-click resolver
pill, and round-trip through save/load via an XRecord blob.

Also includes docs/command_reference.md (a statically generated reference
of every registered command and its prompt sequence) and
docs/named_parameters_design.md + docs/backlog.md, which hand off the next
queued feature (a named-parameter/expression table) and consolidate every
deliberate scope-down and open gap found along the way, so a fresh session
has a complete starting point.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 22:19:23 +02:00
Hakan Seven d35a93c6e8 Avoid reserved MCP session argument 2026-09-07 19:34:31 +03:00
Hakan Seven 2ebad14586 fix(web): capture save previews from the browser canvas
Capture the rendered canvas during the clean frame instead of requesting synchronous GPU buffer readback. Preserve embedded previews and allow saving when canvas readback is denied. Add a browser save and reopen regression check.

Fixes #1021
2026-09-06 13:14:56 +03:00
Hakan Seven cb88f2ded6 Accelerate native MCP workflows 2026-09-05 19:03:16 +03:00