Commit graph

28 commits

Author SHA1 Message Date
Kayshen-X 0a2fa796cb fix(topbar): show the live connected-agent count
The TopBar agent chip hardcoded `agent_count: 0`, so it always
painted the empty 'Agents & MCP' set-up affordance even after the
user connected a provider in Settings → Agents. It now reflects
the real count of connected providers (`agent_settings.connected`).

The chip's '{N} agent' label keyed `topbar.agentSingular`, which
was missing from every locale table — the chip rendered the raw
key. Added the key to all 15 locales.
2026-05-22 11:40:19 +08:00
Kayshen-X 90fad0e17d fix(editor): clippy needless_range_loop in ai_chat_transcript
Use `messages.iter().enumerate().skip(start)` instead of the
explicit index loop `for i in start..messages.len()`; clippy's
`-D warnings` gate on Rust 1.94 trips on the former. Also bump
the casement submodule to da0bf09 so its .gitattributes forces
LF for source files (fixes Windows CI `cargo fmt --check` on
the vendored fork).
2026-05-21 22:33:10 +08:00
Kayshen-X 2aacde0ce2 style: apply rustfmt to the workspace
cargo fmt --all -- --check was failing on CI after the recent
feature work landed unformatted (insert_<comp> MCP tools,
Component-Browser panel, Design-MD panel, op-i18n locale tables,
op-opmerge). Running cargo fmt --all touches 48 files; no behaviour
change.
2026-05-21 22:03:43 +08:00
Kayshen-X 1902d57807 feat(editor): add UIKit component-browser panel
Closes the last TS-vs-Rust parity gap — the Rust shell lacked the
TS `component-browser-panel.tsx` (UIKit library browser +
click-to-instantiate).

- op-editor-core: `uikit.rs` with `UIKit` / `KitComponent` /
  `ComponentCategory` types + a built-in starter kit (6 components
  spanning button/input/card/nav/layout/feedback) as PenNode
  templates; `EditorState::instantiate_kit_component` deep-clones
  with fresh ids and translates the whole subtree to the drop point
  (children carry document-absolute coords).
- op-editor-ui: `component_browser_panel.rs` floating draggable
  panel — header (close), category pills (filtered to non-empty),
  3-col card grid with name + scaled preview rect; kit-id + search
  filters applied.
- op-host-native: paint at §11.5 (below the Design-MD panel),
  `dispatch_component_browser_press`, drag lifecycle, shared
  `over_topmost_panel` helper covers both top-most panels across
  wheel / pan / right-press / cursor_hint / layer-hover / 4
  overlay-hover blocks + align hover + stale-hover clear.
- op-host-desktop: View-menu toggle, `drain_component_browser_insert`
  places at the viewport centre.
- op-editor-core: `active_children`/`active_children_mut` /
  `ensure_pages` symmetric `pages: Some([])` fallback —
  inserts land in `doc.children` and survive a subsequent
  `add_page` (which migrates them into Page 1).
- op-i18n: new `componentBrowser.empty` × 15 locales.

Bumps vendor/jian for the rebased `DesignMdSpec` schema + the
`jian pack` designMd-filter for packaged apps.
2026-05-21 21:24:12 +08:00
Kayshen-X 6e012049e4 feat(editor): add Design-MD panel and complete i18n coverage
Design-MD panel — closes the last TS-vs-Rust parity gap:
- New floating op-editor-ui design_md_panel + design_md_markdown
  renderer: collapsible theme/colour/typography/component/layout/
  notes sections, colour swatches, inline markdown highlighting.
- op-editor-core: parse_design_md parser + panel UI state.
- Host: View-menu toggle, top-most paint + hit-test, drag,
  .md import/export; bumps the vendor/jian DesignMdSpec pointer.

i18n coverage:
- Git panel, merge/conflict/error dialogs and GitError messages
  routed through op-i18n; git locale tables split into
  <base>_git.rs under the 800-line cap.
- Closed 10 app-wide hardcoded-string gaps (AI chat, Figma import,
  file menu, layer context menu, property-panel fill, update /
  file-picker / load-error dialogs, accesskit labels).
2026-05-19 22:29:22 +08:00
Kayshen-X b8f030b3bb feat(desktop): in-app Git panel with branch, diff and merge UI
The floating Git panel — opened from the View menu — shows branch,
working-tree status and recent commits, and offers commit / refresh /
pull plus one-click branch switching. Clicking the status line, a
commit row or a conflicted file opens an in-panel scrollable
unified-diff viewer (the panel widens to 620 px with ▲/▼/✕ controls
and per-line colouring). Each non-current branch row carries a "⤵"
button that requests an isolated worktree merge.

GitPanelState / GitDiffView / GitPanelAction are plain data on
op-editor-core so the widget layer stays wasm-clean — it never calls
git itself. Diff rendering is split into git_panel_diff.rs and the
native press dispatch into git_press.rs to honour the 800-line cap;
the panel is hit-tested before the right-rail blocks so its wide
diff mode cannot lose clicks to the property rail underneath.
2026-05-18 21:45:21 +08:00
Kayshen-X e775fd49c4 feat(desktop): winit shell platform integration
Add five native-platform features to the winit desktop host
(op-host-desktop), closing the gap with the Electron app:

- Native menu bar (muda) — File / Edit / View / Help plus the macOS
  app menu; selections route to the same host actions the keyboard
  shortcuts use. Gated to macOS / Windows — muda needs GTK, which
  this winit build does not link, so Linux keeps the in-canvas File
  menu.
- Auto-update — a background probe of the GitHub releases API
  reports status into the settings System tab; a found update
  offers to open the download page, and a "Check for Updates" menu
  item re-runs the probe.
- File association — argv parsing opens a .op / .pen document on
  launch; [package.metadata.bundle] declares the OS-level handler.
- Window-state persistence — position / size / maximized restore
  across restarts, with an off-screen guard for monitor changes.
- Drag-and-drop — dropping a .op / .pen file opens it.

Codex review round 1 findings (1 MAJOR + 3 MINOR) all addressed:
monitor-aware restore, failed-startup geometry guard, single-flight
update probe, case-insensitive extension match.

Also sink the agent-settings modal's hand-maintained EN/ZH string
table into the canonical 15-locale op-i18n tables, so the settings
chrome (including the new auto-update strings) is fully translated;
agent_settings_i18n.rs is now a thin op-i18n adapter.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-18 08:29:36 +08:00
Kayshen-X ebe0e0bf0f feat(ai): polish chat panel with streaming, tool-calls, thinking, images
Restructure the floating AI chat transcript from flat text bubbles
into a structured view:

- ChatMessage carries thinking text, tool calls and images plus
  per-block collapsed flags and a streaming flag. Image ids come
  from a process-global counter so a fresh ChatState cannot collide
  with the native decode cache.
- ChatPoll splits provider deltas into text / thinking / tool_calls;
  apply_poll_to_message folds them into the in-flight assistant
  message and clears streaming on the terminal Done. The no-provider
  error path also ends the stream and drops staged attachments.
- New RenderBackend::draw_image (default no-op) backed by a bounded
  FIFO decode cache + aspect-fit in the native skia backend; web
  degrades to a framed placeholder.
- New ai_chat_transcript widget: deterministic layout shared by
  paint and hit-test (no live text measurement), collapsible
  thinking / tool-call blocks, a streaming caret + typing-dot
  animation, and image thumbnails.

Reviewed with Codex (3 rounds to clean).
2026-05-18 08:23:31 +08:00
Kayshen-X 25e9739e57 fix(canvas): codex review round 4 — arc clamp, path hit-test, drag cleanup
Addresses the remaining round-4 codex findings (the `short_src`
byte-slice panic + the arc-handle reverse-iteration fixes already
landed via an earlier sweep).

- `cmd_set_ellipse_arc` clamps `sweep_angle` to ±360° — an API /
  MCP sweep beyond a full turn just over-draws; it now persists a
  sane single-revolution value.
- Path hit-test (`point_in_node`) follows the flattened, bezier-
  aware outline instead of the bounding box: a curved or thin path
  no longer selects empty bbox space, a zero-height stroked path
  stays clickable, and a filled closed path is hittable across its
  interior (new `point_in_polygon` even-odd test).
- The viewport-less `apply_release` now commits / clears
  `path_anchor_drag` + `arc_handle_drag` (parity with
  `apply_release_with_viewport`) so a drag can't leak across that
  release path.

op-editor-core 242 / op-editor-ui 157 / op-host-native 21 tests green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 23:00:56 +08:00
Kayshen-X 5b6874b7d8 style: apply rustfmt across the AI-subsystem crates
CI's Rust Check runs a workspace-wide `cargo fmt --check`. Reformat the
new op-acp / op-ai-skills crates and the Part A chat changes to rustfmt
canon. Also sweeps two files an earlier commit left non-compliant
(canvas_viewport_paint.rs, op-pen-loader/adapter.rs) so the workspace
check is clean. Formatting only — no behaviour change.
2026-05-17 22:50:27 +08:00
Kayshen-X 4adfa38bae feat(ai): chat image attachments + per-provider thinking/effort
ChatRequest gains an attachments field; ChatState carries a per-turn
thinking mode, effort level and staged attachments (capped at 4 files /
5 MiB, attachment-only sends allowed). The chat panel grows a controls
row (thinking / effort / attach) and a dedicated attachment-chip row,
with hit-test and paint sharing one input-block origin.

All five providers consume the knobs — Claude maps thinking onto the
SDK token budget, Copilot onto reasoning_effort, the CLI / built-in
transports prepend an in-band directive, the HTTP transport adds body
fields; attachments spill to a private per-turn temp dir (cleaned on
drop) or inline base64. Also wires op-ai-skills into the built-in
provider and op-acp in as the AcpProvider chat backend.
2026-05-17 22:44:28 +08:00
Kayshen-X a459a29825 fix(canvas): a filled closed path no longer draws an implicit stroke
The round-3 closed-path fill left the stroke loop unconditional, so
a closed path with a fill but no explicit stroke was filled AND
outlined in the fill colour. Now the stroke paints only for an
explicit `node.stroke`, or — with no stroke — only when the path is
unfilled (so a bare path stays visible). op-editor-ui 176 tests green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 19:37:50 +08:00
Kayshen-X 0428c6e17b fix(canvas): codex review round 3 — sweep sign, path bounds, closed fill
Addresses the 3 CONCERNs from the third codex review.

- `signed_sweep`: a negative-sweep drag that collapses onto the fixed
  endpoint now snaps to a full -360° circle instead of 0° (mirrors
  `norm_sweep`'s positive 0 → 360 rule) — a negative arc no longer
  silently loses its sign in that degenerate case.
- Path fallback sizing (`path_to_payload`): an unsized path now
  derives its width/height from the handle-aware
  `path_bounds_from_anchors` (cubic extrema included) instead of the
  endpoint-only point bbox, so handles bowing past the anchors no
  longer under-size the scene node.
- Closed-path fill: a closed `Path` with a fill now paints its
  enclosed area via `fill_polygon` over the flattened outline — was
  stroked-only, so authored fills rendered as bare outlines.

Verified against op-editor-core 239 / op-pen-loader 21 / op-editor-ui
155 (op-host-native not test-built — an unrelated in-progress
AIChat thinking/effort change in the working tree leaves its
`AIChatHit` match non-exhaustive; `signed_sweep` is a pure-fn change).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 19:31:41 +08:00
Kayshen-X 4794e323ac fix(canvas): codex review round 2 — drag history + closed paths
Addresses the 4 CONCERNs from the second codex review.

- No-op undo: arc + path/handle drags now mutate nothing until the
  cursor first travels — a press-release leaves the document and
  undo stack untouched. Once the drag has moved, every event keeps
  writing (so a drag back to the start point still lands), gated on
  `is_move || already_moved`. This closes the hole where a ghost-
  handle press-release created a handle with no undo entry.
- Negative arc sweep: `signed_sweep` keeps the sign of the arc being
  dragged, so an MCP-authored counter-clockwise (negative) sweep no
  longer flips to the major arc under a canvas drag.
- Closed paths: `path_closed` threaded through NodePayload +
  SceneNode; `flatten_path` appends the last-anchor → first-anchor
  closing segment (cubic or straight) so a closed canonical path
  draws its closing edge.

op-editor-core 235 / op-pen-loader 21 / op-editor-ui 148 /
op-host-native 64 / op-host-desktop 21 tests green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 19:16:47 +08:00
Kayshen-X 82d33e27df fix(canvas): arc-sector hit-test handles a negative sweep
A negative `sweep_angle` covers the angular range `[start + sweep,
start]`; the hit-test compared against `sweep.abs()` from `start`,
rejecting points that are actually inside such an arc. Normalise to
a forward sweep before the angle-window test.

Self-review follow-up to the arc/pen-handle work (the codex second
review stalled mid-run). op-editor-ui 148 tests green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 18:56:04 +08:00
Kayshen-X 442dbabb78 fix(canvas): codex review — rotation, arc hit-test, path bounds
Addresses the first codex review of the arc + pen-handle features.

BLOCKs:
- Rotation: the arc + pen-handle overlays and the host hit-tests now
  account for node rotation. The overlay paint wraps in save/rotate
  like the selection overlay; the hit-tests + drag math un-rotate the
  cursor into the node's local frame via `rotate_point`.
- Arc ellipse hit-test: a pie / arc / donut now hit-tests against the
  actual sector — the missing wedge + the donut hole are no longer
  selectable (was always the full oval).
- Arc no-op undo: `ArcHandleDragState` gains `start_doc`; the move
  handler gates `moved` on real cursor travel so a press-release
  pushes no undo entry.

CONCERNs:
- Path bounds: the bezier handle-aware bounds algorithm moved into a
  shared `op_editor_core::path_bounds`; `refit_path_bounds` uses it
  (and is now called after handle / point-type edits) so the loader's
  absolutize scale stays 1.0 — a handle no longer rescales the path.
- `cmd_set_ellipse_arc` now honours the locked/hidden editability
  guard like the other geometry mutators.
- A full-ring donut strokes its two concentric ovals instead of the
  polygon, so the radial seam is not drawn.

op-editor-core 235 / op-editor-ui 148 / op-pen-loader 21 /
op-host-native 64 / op-host-desktop 21 tests green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 18:07:11 +08:00
Kayshen-X 112d1f08bb feat(canvas): pen bezier handle editing — render, handles, drag
Completes pen bezier-handle editing on top of the Stage-1 data model.

- canvas_viewport_paint: `flatten_path` — Path nodes with anchor
  control handles render as tessellated cubic Beziers (16 steps /
  segment); handle-free paths keep the straight `points` polyline.
- canvas_viewport: the Pen-tool anchor overlay now draws each
  anchor's two control handles (line + dot), with a faint "ghost"
  dot offset from the anchor when a handle is unset — grab it to
  create the handle. `path_handle_positions` resolves real / ghost
  handle positions, shared with the host hit-test.
- op-host-native: `path_anchor_hit` now distinguishes anchor body
  vs handle_in / handle_out (`AnchorDragTarget`); `PathAnchorDragState`
  carries the target, the anchor's fixed position, and the Shift
  state. The move handler drags the anchor or a handle — a handle
  drag sets the anchor's point type on first motion (Shift =
  independent/broken, else mirrored/smooth) so `set_path_anchor_handle`
  mirrors the opposite handle. Release commits history only on
  actual motion.

op-editor-ui 148 / op-host-native 64 / op-host-desktop 21 /
op-pen-loader 21 tests green (+3 flatten-path units).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 17:47:08 +08:00
Kayshen-X 79b51573dd feat(editor): pen anchor bezier-handle data model + setters
Stage 1 of pen bezier-handle editing — the data + command layer.

- op-editor-core: `EditorState::set_path_anchor_handle` (set / clear
  an anchor's in/out handle; a `Mirrored` anchor keeps both handles
  collinear) + `set_path_anchor_point_type` (switching to `Mirrored`
  snaps the handles collinear). New `PathHandleSide` enum.
- op-pen-loader: `AnchorPayload` (absolute-coord anchor + resolved
  handles + point-type code) on `NodePayload.path_anchors`;
  `absolutize_path_anchors` now resolves the schema's anchor-relative
  handle deltas into the same absolute frame as `points`.
- op-editor-ui: `SceneAnchor` + `ScenePointType` on
  `SceneNode.path_anchors` so the painter + host can read the
  editable handles.

op-editor-core 234 / op-pen-loader 21 / op-editor-ui 145 tests green
(+3 handle-setter units).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 17:33:44 +08:00
Kayshen-X b7bcd9db12 feat(canvas): ellipse arc drag handles
Adds the canvas drag handles that author an ellipse arc — start
angle, sweep (end) angle, and the donut inner-radius.

- op-editor-ui: `ArcHandle` enum + `arc_handle_positions` (doc-space
  positions of the 3 handles for an Ellipse scene node), re-exported
  from `widgets`. The canvas overlay paints them as filled
  primary-tinted dots for a single-selected Ellipse with the Select
  tool.
- op-host-native: `ArcHandleDragState` + `arc_handle_hit` (checked
  before the resize handles since the sweep grip can overlap the
  right-mid resize handle). Press starts the drag with a history
  snapshot; each move recomputes start/sweep/inner from the cursor
  via `arc_drag_command` and re-applies `SetEllipseArc` (no-history
  apply); release commits the snapshot only when the arc changed.
  Dragging the start handle keeps the end fixed; a sweep collapsing
  to 0 snaps to a full 360° circle.

op-editor-ui 145 / op-host-native 64 / op-host-desktop 21 tests
green (+2 arc-handle-position units).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 17:26:37 +08:00
Kayshen-X bfbe3b161d feat(canvas): render ellipse arcs / pie / donut sectors
Ellipse nodes with authored arc geometry (`start_angle` /
`sweep_angle` / `inner_radius`) were always painted as a full oval —
the arc fields never reached the painter.

- NodePayload + SceneNode gain `arc_start_angle` / `arc_sweep_angle`
  / `arc_inner_radius`; threaded through `ellipse_to_payload` and
  `node_payload_to_scene`.
- canvas_viewport_paint: new `arc_polygon` tessellator (pie wedge =
  centre + outer arc; donut sector = outer arc + reversed inner arc)
  + `paint_ellipse` — full oval when no arc is authored, otherwise a
  filled/stroked polygon. A 360° sweep with no donut hole still
  short-circuits to the plain oval path.

Prep for the arc canvas drag-handle UI. op-editor-ui 143 /
op-pen-loader 21 / op-host-desktop 64 tests green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 17:10:50 +08:00
Kayshen-X 448b39ec6c refactor(panels): split effects paint into property_panel_effects.rs
`property_panel_sections.rs` reached 862 lines after the effect
parameter-stepper work — over the 800-line repo file gate. Move
`paint_effects_section` + `paint_effect_row` + `paint_effect_param_row`
into a new `property_panel_effects.rs` (128 lines) and re-export
`paint_effects_section` from `property_panel_sections` so callers
keep using `sections::*`.

`property_panel_sections.rs` is now 755 lines. No behaviour change;
op-editor-ui 140 / op-host-desktop 64 tests green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 14:45:43 +08:00
Kayshen-X 722445b017 feat(panels): shadow/blur parameter steppers in the Effects section
Completes the Effects-controls gap — each effect row now exposes its
editable scalar parameters:

- op-editor-core: `EffectField` enum + `EditorCommand::SetEffectParam`
  + `cmd_set_effect_param` — writes one shadow param (offset X/Y,
  blur, spread) or a blur/background-blur radius; blur values clamp
  to >= 0, field/effect mismatches reject.
- panels: each effect block paints a parameter row per field —
  `<label> <value> [-] [+]`; the "-"/"+" steppers emit
  `AdjustEffectParam` (the walker computes the post-step value from
  the current one). `effects_section_height` / the action-rect
  walker now take the effects slice so the variable per-kind block
  height stays aligned with paint (`VisibleSections.effect_count`
  retired in favour of the slice).
- both hosts dispatch `AdjustEffectParam` via `SetEffectParam`,
  history-committed.

op-editor-core 233 / op-editor-ui 140 / op-host-desktop 64 tests
green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 14:38:26 +08:00
Kayshen-X e30f3b12b4 feat(panels): effect rows + remove in the Effects section
The property panel's Effects section painted only a header + the
"+" add affordance. It now lists the selected node's effects:

- op-editor-core: `node_effects` read accessor exposes a node's
  `PenEffect` slice (container kinds via `container`, leaf shapes
  directly).
- panels: `NodeSnapshot.effects` carries an `EffectSummary` per
  effect; `paint_effects_section` paints one row per effect (type
  label + a "✕"); `VisibleSections.effect_count` + the shared
  `effects_section_height` keep paint and the action-rect walker's
  y-math aligned through the now-variable-height section.
- `PropertyPanelAction::RemoveEffect(index)` — both hosts dispatch
  it through `EditorCommand::RemoveNodeEffect` (history-committed).

Stage 1 of the Effects-controls gap (rows + add + remove); the
per-effect shadow/blur parameter inputs follow. op-editor-core 227 /
op-editor-ui 161 / op-host-desktop 64 tests green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 14:26:19 +08:00
Kayshen-X 87e9655a59 feat(canvas): wire smart guides into node dragging
Completes the smart-guides gap on top of the align_guides geometry:

- editor: EditorUiState.active_guides — transient guide lines for the
  current drag (view-only, never serialized / undone).
- host: apply_smart_guides() runs after each node-drag translate —
  gathers the moving + sibling AABBs off the layout scene, calls
  compute_alignment_guides, applies the snap offset, stores the guide
  lines; drag release clears them.
- canvas: paints the active guide lines (magenta) over the nodes.

The "grid" half of the matrix row was already implemented
(canvas_viewport::paint_grid). op-editor-ui 140 + op-host-desktop 64
tests green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-17 13:17:16 +08:00
Kayshen-X 6a29fb17c7 docs: translate remaining Chinese source comments to English 2026-05-17 09:33:41 +08:00
Kayshen-X 6f4ab59313 fix: clear clippy -D warnings across the workspace
The op-* crate reorg never ran `cargo clippy -- -D warnings`, so the CI
lint gate failed. Fix every violation surgically: real fixes for
mechanical lints (needless_range_loop, derivable_impls, ptr_arg,
needless_borrow, doc_lazy_continuation, unused_imports, manual_find,
collapsible_match, never_loop, dead_code, complex types via type
aliases) and scoped `#[allow]` for intrusive ones (too_many_arguments
on paint helpers, result_large_err where ToolOutcome / PenNode payloads
are deliberately the Err type).
2026-05-17 01:26:29 +08:00
Kayshen-X 90c1cc4360 style: apply cargo fmt across the workspace 2026-05-17 00:26:15 +08:00
Kayshen-X 5f68ab3c1a refactor: extract op-editor-ui crate
Relocate the widget facade (widgets/, including the Widget trait,
render primitives, the editor-UI compositions, the CanvasViewport
center canvas, the lucide icon drawer, and editor_state_ext), the
theme tokens, the layout-resolved render scene (layout_scene +
layout_scene_hit), and the design-variable aggregation (scene_vars)
out of openpencil-shell-core into a dedicated op-editor-ui crate.

The canvas widgets (canvas_viewport*) stay inside op-editor-ui rather
than splitting into a separate op-canvas crate: they depend on the
widgets/ siblings editor_state_ext + icons and on the Widget trait, so
a clean mechanical split is not possible — per the task's explicit
allowance not to force a fragile split.

op-editor-ui's lib.rs mirrors the old shell-core crate-root re-exports
(render_backend facade types + jian gesture types + the i18n alias) so
every intra-module `crate::Color` / `crate::theme` / `crate::widgets`
path resolves unchanged — a pure relocation with no path rewrites
inside the moved modules. openpencil-shell-core becomes a thin
re-export shim (`pub use op_editor_ui::{widgets, theme, ...}`) so the
hosts keep resolving `openpencil_shell_core::*` until the Task 7.3
host rename dissolves the crate. The widgets_static integration test
moves to op-editor-ui/tests with its imports rewritten. The widget
boundary script's reverse-check path is updated to the new crate.
No behaviour change; all tests move with their code.
2026-05-16 23:33:47 +08:00