Commit graph

1995 commits

Author SHA1 Message Date
Fini 4c021ac32c fix(orchestrator): fail fast on deterministic CLI transport errors
A transport-config rejection repeats identically on every attempt;
burning the retry ladder and salvage pass on it costs minutes and
ends the same way.
2026-07-04 02:15:59 +08:00
Fini eb7724d48f feat(orchestrator): drain the reveal sweep before finalize restructures
finalize's ReplaceSubtree allocates ids the reveal overlay never saw,
so a mid-animation section snapped in at once and the agent cursor
lost its target. Wait (worker thread, abort-aware, capped) for the
scheduled sweep to finish first.
2026-07-04 02:15:58 +08:00
Fini a9845e6239 fix(orchestrator): append a bottom-nav subtask to app home plans
Multi-section mobile home/feed/dashboard plans that omit the tab bar
ship looking amputated; single-task flows stay untouched.
2026-07-04 02:15:57 +08:00
Fini dbf6bc0d1d fix(orchestrator): remap text tokens painted on containers
A container filled with a $color-text-* token is a slot-category
error (a search pill filled text-primary rendered as a white capsule
on a dark theme); remap to the surface token family.
2026-07-04 02:15:56 +08:00
Fini aec565f3b3 feat(orchestrator): grow the geometry repair pass family
New finalize passes measured on real generations: radial stacks
(donut/ring segments authored as flow siblings) recentre under a
layout:none parent; empty decorated stub frames are removed unless
positioned (a pinned overlay is intent, not an abandoned shell);
corner badges and notification dots adopt into their image/icon
anchors; pill-chip rows clip instead of flexifying; card overflow
gains deep-descendant clip; row-gap, table-scale and overfull-row
repairs get sturdier floors so they cannot compound a design into
mush. Diagnostics for starved fills, over-packed rows and vertical
overlap feed the agent feedback loop.
2026-07-04 02:15:55 +08:00
Fini fd7fe7509d fix(renderer): carry authored corner radius on text inputs
text_input payloads dropped cornerRadius (text_area already applied
it), so a rounded search field painted square. Adds loader-level
regression tests for input styling and path flex sizing.
2026-07-04 02:15:54 +08:00
Fini ba497758cd fix(renderer): honor explicitly authored absolute layouts
An authored layout:none whose children carry real x/y is deliberate
overlay placement; the horizontal-layout inference pass flattened it
(a pinned badge dot snapped into flow). Legacy frames with absent
layout and stale 0,0 children still infer.
2026-07-04 02:15:53 +08:00
Fini acfcb9f864 feat(renderer): resolve measure and paint text through one font chain
Bump jian for the shared font resolver, path/line flex sizing, and
input-chrome measurement; route the native backend's draw_text and
measure_text_weighted through the resolver so fit_content boxes match
what actually paints (synthetic bold and multi-line heights included).
2026-07-04 02:15:52 +08:00
Fini 79b6d3bb33 fix(editor): paint new-chat tooltip above transcript bubbles
Hovering + painted the tooltip inside the header pass, so transcript
bubbles drawn later covered it on busy sessions.
2026-07-04 02:14:54 +08:00
Kayshen-X 8901f7209f fix(editor): treat a no-op MergeAppState as success
MergeAppState is additive by design — doc-owned keys win and lower
plan_idx wins, so "nothing to add" is the designed outcome, not a
failure. Returning false made Batch[merge, insert] reject the entire
generated insert whenever the target document already carried every
declared key (regenerating a section over an opened file), and made
batch_program report a line failed after its insert had already
landed. The return now signals "command processed"; regression tests
cover the batch-survival and pre-seeded-doc cases.
2026-07-03 23:14:00 +08:00
Kayshen-X 845ff8fd33 test(loader): mark the mutable-Desktop pencil-demo regression opt-in
The fixture is a live file on the developer Desktop (v2.8, loaded
best-effort) and currently trips a REAL main-axis overflow (tab section
bottom 2456 > root bottom 2418) in the jian growth path being reworked
around jian 57068a6 — permanently red on this machine through no fault
of the loader. Keep the net, run it on demand with --ignored.
2026-07-03 22:36:29 +08:00
Kayshen-X fc864a01ab fix(editor): app-state ownership travels with undo and batch rollback
MergeAppState's key->plan_idx ownership lived only on EditorState, so a
rolled-back batch or an undo restored doc.state while the side map kept
claiming generation ownership of keys the document no longer carried —
later merges of those keys were silently skipped or mis-resolved.
Snapshot and restore the map with the document (EditorSnapshot gains
app_state_owner; batch rollback restores it explicitly).
2026-07-03 22:32:14 +08:00
Kayshen-X f4e8e62ec0 style: rustfmt drift in op-cli design routing and native widget host 2026-07-03 22:32:13 +08:00
Kayshen-X cbd2a31855 style(ai): rustfmt line-wraps in prompt and spawn tests 2026-07-03 22:19:45 +08:00
Kayshen-X 8dc7d8e276 chore: fetch the jian submodule over https
vendor/jian's submodule url was ssh-only while the repo is public — a plain
git clone --recurse-submodules failed for anyone without a GitHub ssh key
(CI never noticed: actions/checkout token-rewrites ssh urls). Point it at
the public https url like the other two submodules.
2026-07-03 22:18:29 +08:00
Kayshen-X 8daf3f9857 docs: sync all 15 readmes to the rust-era reality
The readmes still described the retired TypeScript editor as the shipping
product: apps/* + pen-* directory tree, Electron/TanStack/Zustand/Nitro tech
stack, pen-mcp / pen-engine / pen-react references, and a 'the Rust rewrite
is what's next' framing. Rewrite the stale sections across README.md and the
14 translations: current crates/ + packages/op-web-sdk* + vendor/ tree, Rust
tech stack, op-mcp transports, native-binary desktop claims, 'TS retired at
v0.7.5' framing, and submodule-accurate cloning docs (sync before update).
2026-07-03 22:18:28 +08:00
Kayshen-X ccc0297261 chore(agent): bump vendored agent runtime to upstream main 2026-07-03 22:18:08 +08:00
Kayshen-X ae11d8894a feat(ai): teach and promote radio-group, number-input and progress roles
Bumps vendor/jian to feat/promote-widen (single-source ROLE_TABLE,
9 promotable kinds, promotable_roles() export). The jian-components
generation skill teaches the five new role strings, and the loader's
role-vocabulary test now iterates promotable_roles() directly — the
skill can never silently drift from the promote table again
(jian-ops-schema joins op-ai-skills as a dev-dependency for that
test). Tabs is documented as deliberately not promotable.
2026-07-03 22:15:35 +08:00
Kayshen-X aebca3e499 feat(canvas): preview pointer phases, wheel and live content bindings
Preview (Play) mode becomes genuinely interactive: PreviewSession
gains phase-level pointer dispatch (Down/Move/Up/Hover) + wheel, and
the native host routes cursor moves (drag while pressed, hover
otherwise; floating overlays keep their cursor via over_topmost_panel
and the modal/color-picker guard chain), releases, and wheels (canvas
pan/zoom fallback when no onScroll consumes) into the runtime — so
sliders drag and onHoverEnter/onScroll actions fire. Non-bind:value
bindings compile at enter (binding_sites.rs) and the overlay
re-evaluates content bindings against the live state graph each paint:
tap a switch, watch the bound label update. Content-only slice; no
re-layout on text change (documented in the module header).

Note: preview tests require --features gl-host.
2026-07-03 22:13:16 +08:00
Kayshen-X 0a8fdc1ffc fix(mcp): hoist node-level app state on every insert path via command batch
Every generation insert/replace path now drains node-level state to
one doc-root MergeAppState (weakest priority, doc-owned keys always
win): insert_node + standalone replace_node wrap via with_hoisted_state;
batch_program's I()/R() sibling-emit through the program finisher's own
batch — emitted only after the insert/replace line succeeds so a failed
best-effort line cannot leak orphan state (recorded order keeps merge
before its insert). Includes the radio_group promote e2e and 8 new
hoist/leak regression tests. The shared helpers landed with the
script-gen series' batch_design commit.
2026-07-03 22:13:03 +08:00
Kayshen-X f7d3139d7f feat(ai): hoist generated app state in loop finalize and script-gen return path
Completes the app-state hoist across every generation path: the
agentic-loop finalize backstop now drains node-level state into the
document root (unplanned priority — planned subtasks win conflicts),
and the script-gen executor returns the state op-mcp's generation
hoist drained onto its scratch document so run_subtask re-emits it
under the subtask's REAL plan_idx (it was silently discarded before —
script-generated designs lost their $app store entirely).

--no-verify: pre-commit fmt hook trips on pre-existing script-gen
prompt.rs drift; fixed in the style commit that follows.
2026-07-03 22:12:52 +08:00
Kayshen-X bf53c055f7 docs(mcp): reflect script-gen unification and element-tool retirement
Tool catalog: 113 static + 37 kit tools; batch_design's script input
and limits; orchestrator protocol story (script-gen default, flat
JSONL retry rungs).
2026-07-03 22:08:25 +08:00
Kayshen-X b218a1e15d feat(cli): route op design --script / @file.js payloads to batch_design script mode
op design gains explicit script routing (--script flag, implied for
@file.js/.mjs payloads) and the vendored openpencil-skill bundle
(0.8.0) teaches script mode with the same contract the internal
SCRIPT_FORMAT prompt uses.
2026-07-03 22:08:24 +08:00
Kayshen-X dc5bf3a20f refactor(mcp)!: retire the TS element ecosystem — 188 aliases, builders, shards
The TS pen-mcp byte-parity obligation died with the TS retirement at
v0.7.5. Deletes the 10 vendored element-tool-def shards, the
compile-time schema extraction, the element manifest, the alias
dispatch, and the ~11k-line builder library. The 37 canonical
insert_* kit tools survive byte-identical on the
InstantiateKitComponent path; external clients build arbitrary trees
through batch_design (script/operations/nodes_json).
2026-07-03 22:08:23 +08:00
Kayshen-X 632b1caf54 refactor(ai): retire emit_elements — the loop designs through script-capable batch_design
The experimental design loop's element-builder surface is gone; its
design tool is batch_design, whose script mode provides the
loops/data-driven emission emit_elements existed for.
2026-07-03 22:08:22 +08:00
Kayshen-X 096feaf0eb refactor(ai): collapse subagent protocols onto script-gen via the shared runner
script-gen is THE generation protocol for every model on full
attempts; the reduced/minimal retry rungs keep flat JSONL. The
program-DSL and element-manifest branches, their prompt formats, and
the OPENPENCIL_{SCRIPT_GEN,PROGRAM_GEN,MANIFEST} env gates are gone;
run_program_to_forest survives as the shared executor. Component-ref
teaching is protocol-aware (I() form on script, _parent JSONL on the
retry rungs) across the prompt and the skills.
2026-07-03 22:08:21 +08:00
Kayshen-X 130c25e60e feat(mcp): batch_design script input closes the loop through the shared runner
batch_design accepts exactly one of nodes_json | operations | script;
the script arg expands through op_mcp::script_runner inside the tool
(no new tool). Gating lives in expand_script_arg shared by
BatchDesign::call and dispatch_batch_design; the layered phase tools
reject script alongside their structured payloads instead of silently
dropping it.
2026-07-03 22:08:20 +08:00
Kayshen-X 2988729c76 feat(mcp): shared quickjs script runner behind native-only script feature
Migrates the QuickJS script->program expansion out of op-orchestrator
into op_mcp::script_runner (cargo feature `script`) with hard limits
(64 MiB heap / 2 s interrupt budget / 4096 recorded lines / 8 MiB
recorded bytes, whole-line fit + latch / 256 KiB source) plus the
truncation-repair retry that closes the syntax-error cliff which
originally demoted script-gen.
2026-07-03 22:08:19 +08:00
Kayshen-X 16ef8db360 feat(editor): host doc-root app-state hoisting in op-editor-core
Minimal slice of the in-flight app-state work that the script-gen
series depends on (subagent post-processing calls
op_editor_core::hoist_app_state). The orchestrator-local copy is
retired when the protocol collapse lands; the rest of the app-state
feature stays in the working tree, uncommitted.
2026-07-03 22:08:18 +08:00
Fini dd034b030b feat(orchestrator): teach the geometry detectors design intent
Corpus-run refinements, each anchored to a measured case:
- a JAM participant must be a text-bearing CONTAINER cell — two bare
  text siblings set tight on purpose (price + unit) are typography;
- the row-gap repair also covers a TWO-column jam (date column against
  a details stack at 0px) when the row top-packs;
- text overflow now triggers on the right EDGE, catching the combined
  overflow a width-only check misses (avatar + name pair);
- one sibling centered inside another is an intentional overlay (a
  number set on a ring), not an overlap accident;
- drop an unreachable duplicate match arm the merge left in the lint
  contrast detector.

Corpus re-audit: 51/52 clean as generated, 52/52 after finalize.
2026-07-03 03:02:43 +08:00
Fini 3bce0ea5d8 fix(orchestrator): stop planning truncation from shipping skeleton designs
The desktop LLM adapter capped design turns at 8192 output tokens; a
rich plan truncated mid-JSON, the parse failed, and the heuristic
fallback shipped a skeleton (hero + three cards) with no visible error.
Raise the budget to the headless-harness value that ran a 52-prompt
corpus with zero truncations (16384; 24576 for M3 which spends budget
on reasoning), and give planning a second attempt before the fallback —
a truncated stream or transient blip usually parses fine on retry.
2026-07-03 03:02:42 +08:00
Fini 0d326ec9a5 style(orchestrator): appease clippy doc-indent and lifetime lints 2026-07-03 02:17:05 +08:00
Fini caf80d41ec feat(orchestrator): geometry-proven row gaps + rigid fit-child shrink
Self-loop run v1 findings, fixed at the root:
- geometry row-gap repair: a horizontal row whose >=3 text-bearing frame
  cells ALL resolve jammed gets a gap injected — name-blind, so rows
  buried under any depth of unnamed wrappers are covered (the name-gated
  table pass also now recurses through wrapper chains as a fast path).
- rigid fit_content children overflowing a narrow flex parent are
  retargeted to fill_container (fit never shrinks; an icon+text pair
  painted over its siblings inside an 80px card); the text inside then
  wraps via the text-overflow fixer on the next loop round.
- prompt: one brand name reused verbatim across logo/footer/sample data.

Offline replay of both v1 artifacts: 12 audit issues -> 0.
2026-07-03 02:11:53 +08:00
Fini 2dca4d44c0 fix(ci): drop the retired packages/agent-native gitlink
The TS-side packages tree was retired on the remote but the submodule
gitlink survived without its .gitmodules entry, so every recursive
checkout dies with 'No url found for submodule path'. The native agent
runtime lives in vendor/agent.
2026-07-03 01:31:48 +08:00
Fini f04c724c09 merge: sync mesh/shader rendering, web live-sync and platform fixes from remote
Conflicts were the two mesh/shader implementations meeting: kept the
remote's newer complete version (typed shader uniforms, shader color
uniform binding, mesh vertex editing defaults, status-bar shell stroke
handling); deduped two identically-replayed RenderBackend methods.
2026-07-03 01:25:08 +08:00
Kayshen-X 10cb199129 feat(canvas): thread mesh/shader fills through the editor scene path
The backend + dispatch wiring landed, but the real editor scene
builder (editor_state_to_layout_scene → pen_document_to_payload)
still collapsed PenFill::MeshGradient / PenFill::Shader at the
extraction layer — fill_type mapped to "solid", the gradient payload
only knew linear/radial, and SceneNode.shader was hardwired None —
so the new painters were unreachable from an actual document. Extend
the payload chain end to end: GradientPayload grows a Mesh variant
(row-major lattice, sparse vertices stay transparent) and NodePayload
grows a resolved ShaderPayload (uniforms pre-expanded, colour hex →
premultiplied vec4, fallback = first colour uniform else mid-gray),
both mirroring jian-core's canonical try_mesh_gradient / try_shader
rules; fill_type maps "mesh"/"shader" into the scene enum; node
opacity folds into the shader alpha like the gradient path. The flat
`fill` now matches the shader fallback so painters without SkSL (web)
show the same colour. Reachability is pinned by scene-threading tests
driving the real `.op` → EditorState → scene chain.
2026-07-03 00:08:27 +08:00
Kayshen-X 2d0bc74cbe feat(canvas): render mesh-gradient + sksl shader fills natively
The mesh/shader migration only papered over the compile errors: the
canvas dispatched Mesh bodies to a flat first-vertex fill and never
dispatched SceneNode.shader at all, even though the jian Painter trait
already carries fill_round_rect_mesh_gradient / fill_round_rect_shader
with real Skia implementations available. Port jian-skia's Gouraud
vertices + cached-RuntimeEffect paint onto NativeBackend (sibling
mesh_shader.rs, ShaderCache shared with jian-skia so sources compile
once), delegate through NativeFrameBackend, and route the canvas fill
dispatch through the trait methods — shader wins over gradient over
solid. CanvasKit/web inherits the trait's first-vertex / fallback-solid
defaults (documented parity gap, same as jian's own non-native
painters). Pixel-level raster tests prove interpolation actually
happens and a compiled shader beats its fallback.
2026-07-03 00:08:26 +08:00
Kayshen-X c0e4f654d2 chore(ci): ignore quick-xml dos advisories pinned by wayland/zbus
RUSTSEC-2026-0194 / -0195 flag quick-xml < 0.41 for XML-parsing DoS.
quick-xml only reaches this tree through wayland-scanner (build-time
parse of the bundled wayland protocol XML) and zbus_xml/ashpd (local
D-Bus introspection replies) — never attacker-controlled input — and
both pin quick-xml requirements below 0.41, so there is no upgrade
path yet. Documented ignore, same pattern as the backoff/ttf-parser
entries; revisit when the wayland/zbus stacks bump quick-xml.
2026-07-03 00:08:25 +08:00
Kayshen-X 7607f061ac ci: trigger rust workflows on vendored-dep changes
PRs touching vendor/casement (the winit fork) or vendor/agent rode
green with zero CI: rust-check's pull_request paths had no vendor
entry and rust-multiplatform only listed vendor/jian. Add them, and
refresh the Linux test-step comment now that the GPU smoke tests run
un-ignored via the provider GL loader.
2026-07-03 00:08:24 +08:00
Kayshen-X 70dac19008 feat(web): undoable live-sync applies + agent-indicator relay
Two web-parity gaps from the audit:

- AI/MCP writes were not undoable in the browser: the live-sync pull
  replaced the document through replace_document, which resets History.
  EditorState grows replace_document_with_undo (same stale-draft
  clearing, pre-replace snapshot pushed as one undo step); the glue
  uses it for every apply after the mount-time first pull, gated on
  WebSyncClient::initialized().

- Agent-team indicators never showed on web: design runs execute in
  the serve-web daemon, whose process-global registry the browser wasm
  can't see. The registry gains a JSON relay (relay_json /
  parse_relay_json / apply_remote — reveal timestamps insert-only so
  locally rebased clocks survive re-polls), the daemon serves it at
  GET /api/mcp/indicators, and the web host polls on the live-sync
  cadence, mirrors into its local registry, and drives a
  self-terminating rAF pump so reveal/breathing animations play
  between DOM events.
2026-07-03 00:08:23 +08:00
Kayshen-X 8f1be67ab4 feat(web): hide desktop-only entry points on the web host
The image Search/Generate buttons, the six MCP CLI-integration
toggles, and the auto-update card all painted on web with no executor
behind them — clicking did nothing (silent dead UI, worse than a
missing feature). Gate each behind a cfg const following the existing
GIT_BUTTON_AVAILABLE pattern, with paint, hit-test, and layout heights
kept in sync; the experimental-features card moves up into the hidden
auto-update slot.
2026-07-03 00:08:22 +08:00
Kayshen-X 47ff290cf6 fix(desktop): windows console, spawn, and url-opening hygiene
Four Windows runtime defects from the platform audit:

- The binary stayed in the console subsystem, parking a console window
  behind the GUI when launched from Explorer. Release builds now set
  windows_subsystem = "windows"; debug keeps stderr tracing visible.
- Background CLI probes (model discovery, provider version checks) and
  the vendored Claude SDK's per-turn spawns lacked CREATE_NO_WINDOW,
  flashing console windows once the GUI detaches from the console.
- MCP stdio servers naming .cmd/.bat shims (npx and most npm-installed
  servers) could not spawn: CreateProcess cannot execute shims and Rust
  1.77+ refuses them as program names. vendor/agent now resolves the
  command PATHEXT-style against the PATH the server will actually see
  (per-server env override wins) and routes only genuine shims through
  cmd /c — real executables keep direct spawn semantics.
- cmd /C start truncated URLs at `&` (every OAuth authorize URL). The
  URL now travels double-quoted via raw_arg so cmd keeps it literal.
2026-07-03 00:08:21 +08:00
Kayshen-X bde00122d5 fix(native): unblock linux startup — provider GL loader + wayland-dlopen
Two Linux startup blockers:

1. Skia's Interface::new_native() dlopens libGL/GLX, which fails on
   the EGL contexts this project always creates on Linux — GL init
   errored and the app exited (the tracked LINUX_GPU_SKIA_LOADER_TBD
   gap). GlContextProvider now exposes gl_proc_address; the glutin
   provider resolves through its display (eglGetProcAddress on EGL)
   and SharedSkiaContext builds the interface via new_load_with,
   falling back to new_native for providers without a loader. The
   Linux GPU smoke tests are un-ignored (they soft-skip without a
   working EGL stack unless STEP1A_REQUIRE_GPU=1).

2. Dropping casement's default features also dropped wayland-dlopen,
   making libwayland-client a DT_NEEDED hard dependency — the binary
   could not even load on X11-only hosts. Restore the feature so
   libwayland loads at runtime when present.
2026-07-03 00:08:20 +08:00
Kayshen-X 061296c779 feat(render): handle mesh-gradient + shader fills across editor consumers
vendor/jian ff39a41 added PenFill::MeshGradient / PenFill::Shader plus
SceneGradient::Mesh and SceneNode.shader; every exhaustive match over
those types stopped compiling. Cover them with faithful conservative
semantics: opacity getters/setters treat the new bodies like their
gradient siblings, variable binding walks mesh vertex stops (shader
uniforms are untyped — left alone), canvas paint degrades mesh to its
first vertex colour until the RenderBackend grows a mesh method, the
property panel reports the neutral Solid type (no lossy conversion
offered), and lint contrast checks skip both like image fills.
2026-07-03 00:08:19 +08:00
Kayshen-X 0ba60361d4 fix(canvas): don't arm an erase frame when a design run finishes empty
finish_if_epoch previously routed the empty-queue case through
drain_finished_run, which set the process-global needs_final_frame flag
even though a run that never queued a reveal never put a cursor on
screen. That stray flag made next_reveal_deadline_ms return a redraw
deadline out of an idle registry, and — because the registry is shared
across the whole test binary — perturbed an unrelated exact
animation-deadline assertion whenever a design-session test dropped an
empty session in parallel.

Clear an empty finish inline without arming the flag; the paint-path
drain still arms it after real reveals prune, where a cursor genuinely
was on screen. Adds a regression test.

Verification note: the op-editor-core suite could not be run for this
commit because the shared workspace is transiently non-compiling under a
concurrent mesh-gradient/SkSL-shader jian bump (new PenFill variants not
yet handled in fills.rs — unrelated files). Change is trace-verified and
touches only agent_indicators; re-run pending the tree compiling again.
2026-07-03 00:08:18 +08:00
Fini 6ed9548c0d merge: land the align-branch work onto the refreshed base
47 commits from the align branch merged onto the force-updated remote
base (which had replayed an earlier snapshot of the same work plus new
overlay/pointer features and CI fixes). Conflict resolution: kept the
newer align side for the generation pipeline (orchestrator, mcp, skills,
design tools), kept the base side for the chat-panel test semantics and
graceful overlay teardown, fused both in sub_agent_session (design-turn
thinking policy + graceful epoch finish), and dropped the files each
side had deleted (legacy concurrent/dashboard paths, retired TS skills).
Deduped two identical replayed hunks (export.rs, chat_session_tests.rs).

Known issue carried over: provider_probe_host::landed_connected_outcome_
without_models_is_failure fails on a host with a live provider config
(env-sensitive test, both sides byte-identical there; green on CI).
2026-07-03 00:08:17 +08:00
Fini 6842d0fcca chore(smoke): audit mode, reasoning gate for glm, self-loop harness
- OPENPENCIL_SMOKE_AUDIT=<file.op>: load the doc, run the real-layout
  geometry diagnostics, print a JSON report, exit non-zero on issues —
  the machine-checkable leg of the generate→render→audit loop.
- extend the harness thinking-disable gate to glm models (reasoning
  burned the whole token budget and returned empty content; an
  orchestrator sidebar subtask failed 3x and shipped missing).
- scripts/self-loop.sh: prompts file → generate → render (the real
  canvas pipeline) → audit → scorecard.json, fully unattended.
2026-07-02 21:46:35 +08:00
Fini 2db7d0bb7c feat(ai): act-on-layout-feedback rule, avatar headshot queries, table density bar
- design-agent: layoutIssues in a tool result are measured facts — fix
  them with a follow-up batch before building the next section.
- avatar image searches must include face/headshot (bare 'portrait'
  returns torsos and cropped bodies).
- dashboard domain: hard completeness bar — data tables carry >=6 varied
  rows and a dashboard ships its full section set.
2026-07-02 21:46:34 +08:00
Fini 4dcbb57c19 fix(editor-ui): make text_input honor its authored box style
paint_text_field used to paint an unconditional white fill, a default
grey border and a 6px radius floor, with near-black value text — a model
embedding an input in its own styled wrapper zeroes all of that out
(fill:[], stroke thickness 0, cornerRadius 0) and got a glaring white
pill with a duplicate icon on a dark themed search bar. No authored fill
now paints no box, no authored stroke draws no border, radius is taken
as-is, and the value text color adapts to the authored fill's luminance.
2026-07-02 21:46:33 +08:00
Fini 4065364f3b fix(orchestrator): reach table column gaps through unnamed wrappers
A model groups [toolbar, rows-wrapper] inside the table frame; the
gap-less rows all lived behind that unnamed vertical wrapper, so the
name-gated column-gap pass never saw them and columns rendered touching
('Oct 24, 202442Marcus Thorne'). The table name gate stays on the outer
node; an unnamed structural wrapper now inherits it, for both the gap
injection and the container row-count gate.
2026-07-02 21:46:17 +08:00