forked from 1b-agent/opencadstudio-upstream
feat: hatch PDF draw order (#1345), numeric CAS (#1348), web automation (#1349), DATALINK table, System theme; honest decode accounting
Upstream issues, fixed: #1345 — hatches plotted at draw_depth 0.0: the plot path cloned models from the hatch cache, which bakes the depth at seed time; the canvas re-reads the live depth map every frame, which is why the editor was right and every export (PDF and native printing — both route through the exporter) was wrong, with hatch-vs-hatch ties broken by HashMap order. The plot path now re-reads the depth map per entity, and the exporter's tie-break ranks follow the editor's own pass order (hatch < image < wire fill < wire < text < wipeout) instead of pinning hatches between fills and wires. Pinned by content-stream operator- order tests (back/front hatches, overlapping hatches, interleaved wire-between-hatches) and a scene test that fails pre-fix. #1348 — set_properties' optimistic-concurrency compare now matches numbers by value (10.0 == 10) through json_values_match, compatible with the shape of upstream PR #1350; nested objects/arrays recurse. #1349 — web automation contract: control protocol 2 (v1 clients still accepted) adds {op:'open', name, data_base64} routed through the guarded open queue; window.ocsControl.ready/request promise wrapper with an ocs-ready event (web/ocs-control.js); the startup donation prompt is suppressed once a control request is seen (opt-in pre-boot via localStorage); docs/automation documents the whole web contract. Also: DATALINK CSV-to-table works on web (picker + bytes through the session registry — was std::fs, silently dead); COLORSCHEME accepts System (prefers-color-scheme on web, AppsUseLightTheme on Windows). Decode accounting, made honest per the fix-of-fix review: into_rgba8 allocates the RGBA destination while the native buffer is alive for every non-Rgba8 layout (L8 5, La8 6, Rgb8 7, L16 6, La16 8 B/px peaks — the formula now says so), GIF bills the screen+frame coexistence at 8 B/px, and TIFF drops the 3x multipliers both ways — tiff 0.11 splits the given budget between frame and scratch (a total ceiling), so the old double-billing refused honest 16-bit GeoTIFFs ~2.25x early while admitting hostile chunk transients at 3x. The image-refusal-unknown-size locale key moves to the group the catalog always claimed (file).
This commit is contained in:
1 parent
84b093748f
commit
2c38de53e2
41 files changed
+1026
-92
No files matched your search
@@ -156,3 +156,45 @@ The repeatable live-editor evaluation draws three isolated entities in one batch
|
||||
```sh
|
||||
python3 docs/automation/mcp_eval.py target/debug/OpenCADStudio
|
||||
```
|
||||
|
||||
## Web automation
|
||||
|
||||
The web build exposes the same control protocol (protocol 2; protocol 1 requests are still accepted unchanged) through two wasm exports on `window.wasmBindings`:
|
||||
|
||||
- `ocs_control_submit(requestJson)` returns a ticket id immediately.
|
||||
- `ocs_control_take(ticketId)` returns the JSON reply once the app has settled the request, or `null` while it runs.
|
||||
|
||||
`web/ocs-control.js` (loaded by `web-app.html`) wraps that pair in a small promise API:
|
||||
|
||||
```js
|
||||
await window.ocsControl.ready; // resolves when the bridge exists
|
||||
window.addEventListener("ocs-ready", () => {}); // ...or listen for the one-shot event
|
||||
const state = await window.ocsControl.request({op: "state"});
|
||||
const reply = await window.ocsControl.request({
|
||||
op: "run", request_id: "line-1",
|
||||
document_id: state.document_id, revision: state.revision,
|
||||
cmd: "LINE 0,0 10,0",
|
||||
});
|
||||
```
|
||||
|
||||
`request` resolves with the final reply, following an `accepted`/`running` operation through `op: "operation"` until it completes, fails, or waits for input. It rejects on timeout (default 120 s, override with `{timeoutMs, pollMs}`) or when the bridge is missing.
|
||||
|
||||
### Opening an in-memory drawing (web only)
|
||||
|
||||
The `open` operation accepts base64 bytes instead of a path, so automation can open drawings it already holds in memory — no OPFS copy, no file picker. The bytes go through the same guarded open queue drag-and-drop uses:
|
||||
|
||||
```js
|
||||
const bytes = new Uint8Array(await file.arrayBuffer());
|
||||
let binary = "";
|
||||
for (const byte of bytes) binary += String.fromCharCode(byte);
|
||||
await window.ocsControl.request({
|
||||
op: "open", request_id: "open-1", name: "plan.dwg",
|
||||
data_base64: btoa(binary),
|
||||
});
|
||||
```
|
||||
|
||||
The operation stays pending until the open settles; if another open holds the slot, the reply reports `result.queued` and the poll opens the drawing as soon as the slot frees. `state.capabilities` lists `open_bytes` on the web build. Native builds keep the path-based `open` and reject `data_base64` with `invalid_request`.
|
||||
|
||||
### Startup prompts during automation
|
||||
|
||||
The first control request of a session marks it automated: a donation prompt that has not been shown yet is dropped, and no new one is queued while control stays enabled. A prompt already on screen is left for its reader — close it with `{"op":"action","name":"close_modal"}`. A web host that intends to automate from the first page load can set `localStorage["opencadstudio.automation"] = "1"` before loading the app so the prompt never appears (the same pre-load mechanism the settings use).
|
||||
Reference in new issue
Block a user