Commit graph

1563 commits

Author SHA1 Message Date
Kayshen-X 281698d95a chore(vendor): bump jian for scroll area primitive 2026-06-14 00:56:15 +08:00
Kayshen-X 8d73345cfe chore(vendor): bump jian for menu widget primitive 2026-06-14 00:56:14 +08:00
Kayshen-X 9734c1f73a chore(vendor): bump jian for select widget primitive 2026-06-14 00:56:13 +08:00
Kayshen-X 82b07847a4 chore(vendor): bump jian for text area widget view 2026-06-14 00:56:12 +08:00
Kayshen-X 5cb9d36ec5 chore(vendor): bump jian for text input widget view 2026-06-14 00:56:11 +08:00
Kayshen-X 949cb5a4b1 chore(vendor): bump jian for widget button primitive 2026-06-14 00:56:10 +08:00
Kayshen-X 9dce2957e6 chore(vendor): bump jian for shared widget tokens 2026-06-14 00:56:09 +08:00
Kayshen-X 42de84c917 refactor(editor): re-export painter contract from jian-widgets 2026-06-14 00:56:08 +08:00
Kayshen-X 0daca70f74 chore(vendor): bump jian for select-all arrow fix 2026-06-14 00:56:07 +08:00
Kayshen-X 46822b1ff5 chore(vendor): bump jian for text_input + scroll modules 2026-06-14 00:56:06 +08:00
Kayshen-X bfc8d1676b refactor(editor): unify Color::with_alpha and Color::to_jian 2026-06-14 00:56:05 +08:00
Kayshen-X d64d4a2dc4 refactor(editor): add Rect::contains, drop local rect_contains copies 2026-06-14 00:56:04 +08:00
Fini 5ba0fb62cb feat(mcp): default v1 element theme to system (spec D2)
Flip the manifest repair-layer default for v1 element kinds from
`light` to `system`, so weak-model designs adapt to the document's
light/dark axis instead of baking light-mode hex. Both prerequisites
are now in place: the orchestrator seeds the 56-token semantic palette
at run start (`-*` refs resolve at paint via scene_vars) and
every v1 builder emits numeric gap/padding in system mode. Explicit
`theme=light|dark` still wins.

ab-v9.3 validation (52 prompts × 4 arms, theme=system default):
- Rendering: 0 dangling $color-* refs across all 208 .op; 207/208
  carry the seeded palette + Mode:[Light,Dark] axis. The D2 grey-ref
  risk does not materialize at corpus scale.
- Structural inertness: theme is injected post-model by repair_args
  and only selects fills; role inference + the contrast post-pass are
  already $ref-aware (role_post_pass resolves a ref to None and skips).
  M3/M5 cannot move on the flip — glm's 15 M3 misses are 100%
  missing-role (model output), theme-independent.
- No collapse: M3 ark 81% / glm 71% / DS 85% / m3-think 94%, 0-1
  garbage per arm. Per-arm deltas vs ab-v9.2 are cross-codebase
  (Kayshen's d31734e2 edited the manifest skill + builders between
  runs) + sampling, NOT the theme flip.
2026-06-14 00:56:03 +08:00
Fini aa25cc2a7e fix(editor-ui): variables-panel wheel scroll + preset toggle test
Two failures surfaced once the casement build blocker cleared and the
`cargo test --workspace` step finally ran on v0.8.0-new:

- wheel_over_panel_scrolls_rows_and_clamps: `over_topmost_panel` ran
  first in apply_wheel and lists the variables panel, so a wheel over
  the panel was swallowed (returned true) WITHOUT ever reaching
  try_scroll_variables_panel — rows never advanced. Move the variables
  scroll handler ahead of the topmost-panel guard; it already swallows
  the wheel over its own rect, so the canvas-zoom guard still holds.

- variables_panel_preset_button_toggles_menu: the second press used a
  +58 y-offset that lands in the open dropdown's SaveCurrent row, which
  intentionally focuses the name input and keeps the popover open (TS
  parity, see anchor_press_does_not_double_toggle). Re-press the button
  itself (+22) so the test exercises the toggle it is named for.

op-host-native lib: 296 passed / 0 failed.
2026-06-13 21:07:24 +08:00
Kayshen-X 4dee479c6b chore: snapshot WIP across editor-core, editor-ui, hosts, mcp, ai-skills
Working-tree snapshot spanning op-editor-core (components, path_edit,
ref_resolve, text_edit, instance_override, image_panel), op-editor-ui
widgets (chat panel, variables, property fill, canvas overlays, ime),
op-host-desktop (chat backends, export, kit_persistence), op-host-native
(font picker, frame backend, pen press), op-mcp (batch_program), AI-skills
prompts, and regenerated shadcn-kit / iconify catalog assets.
2026-06-13 17:59:54 +08:00
Fini ebcb85a569 fix(mcp): emit numeric gap/padding in system-mode builders
theme=system audit (D2 prerequisite): the schema accepts $spacing-*
expression refs in gap/padding, but both Rust layout paths zero them
out — jian-core container_to_style and op-pen-loader gap_value fall
through Expression to 0 — so a ref collapses the layout instead of
resolving. Exactly three emission sites existed: modal_shell's card
padding ($spacing-5) and gap ($spacing-3), and toast's pill gap
($spacing-2). Emit the palette-equal numbers (24/12/8) in every mode,
same pattern as the numeric font-size toast fix (011f4104). A new
catalog-wide invariant test builds all kinds with theme=system and
rejects any expression gap/padding, so future ports can't reintroduce
the class. Color $refs are unaffected — scene_vars resolves fill and
stroke refs at paint.
2026-06-13 01:05:46 +08:00
Fini 05e1e4e2d8 feat(ai): route element manifest by model family (M4)
Replace the global OPENPENCIL_MANIFEST env gate with per-model routing:
manifest defaults ON for the families that cleared the ab-v9.2 KPI gate
(minimax 92% / ark-code 92% / glm 98% / deepseek 83%, all >=70%) and
stays OFF for models without benchmark data — the catalog is a floor
for weak models, not a ceiling for strong ones. The env var remains a
both-ways override (1/true/on forces on, 0/false/off forces off) so
op-smoke benchmarks and rollback keep their one-knob workflow.

Also plumb the selected built-in agent's model id into DesignRequest:
the production chat path always sent model:None, which routed every
model to Full-tier prompts and dead-armed both this gate and the M3
thinking policy outside op-smoke. Live-verified: glm-5.1 with no env
set engages the manifest protocol purely via routing.
2026-06-13 00:52:26 +08:00
Fini a9b0e729fd feat(ai): seed semantic palette at orchestration start
Port the TS applySemanticPalette 56-token palette (22 themed light/dark
colors on a Mode axis, 6 chart singles, 28 numerics) and wake the
dormant variables.rs seeding path. Merge semantics differ from TS:
editor-core set_variables_bulk extends (incoming wins) while TS keeps
existing values, so the snapshot computes the missing set first and
seeds only absent tokens via one MergeThemePreset; rollback removes
exactly the created names/axes when no content survives. Live-smoke
verified: generated .op carries the 56 vars + Mode axis and $color-*
refs resolve at paint.
2026-06-13 00:35:35 +08:00
Fini 9ffaf5980c fix(ai): admit painted childless frames as blank-check content
A childless Frame with explicit stroke or fill is pixel-equivalent to a
childless Rectangle, which the blank check already admits. otp_input's
empty stroked digit slots made perfect manifests read as blank
scaffolding -> retry ladder -> raw fallback degradation (ark emitted
flawless otp manifests twice and got rejected both times). Also
serialize the OPENPENCIL_MANIFEST env tests behind a shared lock --
parallel set/remove races only surfaced in full-suite runs.
2026-06-13 00:35:34 +08:00
Fini fa4130c133 feat(ai): deterministic element-kind hints for manifest sub-agents
ab-v9.1 misses were attention failures, not vocabulary failures: kinds
named literally in the brief (toolbar 5/10) still got hand-composed,
while anti-pattern-named kinds rarely missed. Token-match the subtask
label+elements text (plus the whole brief for single-section plans)
against the catalog, expand via a data-grounded synonym table, and
inject up to 6 nominations as an ELEMENT HINTS block with composite-
first and no-hand-compose rules. ab-v9.2 matrix: 51 FAIL->PASS vs 4
noise-shaped regressions; all four arms >=83% M3-pass, M5 adoption 96%.
2026-06-13 00:35:33 +08:00
Fini 461b77a054 fix(ai): manifest catalog recency placement + composite coverage teaching
Full-tier prompts run ~8k tokens and deepseek kept hand-rolling past a
top-of-prompt element catalog (ab-v9 58% vs Basic-tier 85%). Pull the
element-manifest skill out of priority order and append it last, right
above the output contract, so recency keeps the catalog in attention.
The skill's COVERAGE section now also teaches composite-first checking
instead of only naming examples.
2026-06-13 00:35:32 +08:00
Fini e7ae700678 feat(ai): keep MiniMax-M3 reasoning on design subtasks
M3 with thinking disabled drops to M2.7-level element adoption; route
design sub-agent calls through Adaptive thinking with a 16384 budget
for the M3 family while other built-in models keep Disabled+8192.
Validated by the ab-v9.2 matrix (m3-think arm 92% M3-pass).
2026-06-13 00:35:31 +08:00
Kayshen-X 9fd78d2d8a fix(editor-ui): resolve conflict markers swept into the chat panel during the rebase
The background fmt commit captured the editor-ui pick's conflicted state
mid-rebase; both sides kept (ab-v9 concurrency-chip spacing + tests_paint
module, batch tests_transcript module + footer tests), paint helpers
promoted for cross-module reuse.
2026-06-12 23:36:36 +08:00
Kayshen-X 14482a5d86 feat(variables): panel UX, variant-column color editing, theme presets, web mirror
#18 per-row management (resize edges, search with source indices, scroll
clamp, row overflow menu with delete+undo, inline hex cells), #19 variant-
column-targeted color/boolean writes (setValueForTheme parity, picker
seeds from the clicked column), #20 theme presets (.optheme io, app-level
persistence, shared preset menu), #21 full web host mirror (floating
panel replaces the read-only rail; keyboard/scroll/resize/blur routing).
Fixes the stale right-rail assertions in toolbar_panel_actions test.
Absorbs and completes the concurrent actor's variables-panel WIP.
2026-06-12 23:28:11 +08:00
Kayshen-X 3418fe60af fix(web): route iconify body parse through the widget_host boundary seam
check-widget-boundary.sh F4 forbids op_editor_ui::widgets references
outside widget_host.rs + siblings; the remote-icon fetcher now calls the
new icon_ingest wrapper instead of icon_catalog directly.
2026-06-12 23:28:10 +08:00
Kayshen-X 4c7a2a52a1 chore(build): release packaging scripts, wasm bundle gate with codegen, workspace docs + lockfile 2026-06-12 23:28:09 +08:00
Kayshen-X 036222645c feat(renderer): styled text runs, clip-content threading, image payload fields in the loader 2026-06-12 23:28:08 +08:00
Kayshen-X 3759331f79 chore(i18n): locale keys for pickers, image section, kit + preset surfaces 2026-06-12 23:28:07 +08:00
Kayshen-X 55982477fd feat(cli): codegen commands wired to real tools, status pid, web start json 2026-06-12 23:28:06 +08:00
Kayshen-X d7a079e64d feat(codegen): stored-zip encoder + cancel/page-generation hardening
Dependency-free STORED zip for the web bundle path; pipeline cancel +
whole-page input fallback verified surfaces.
2026-06-12 23:28:05 +08:00
Kayshen-X 296ccb3e31 feat(mcp): DSL programs, codegen workflow, debug screenshot, output-shape parity
batch_design multi-line program executor (per-line best-effort, TS quirks
verbatim, alias-table slash paths), codegen plan/submit/assemble/clean
tools + plan store, debug screenshot args, snapshot_layout/batch_get
shapes, refine postProcess in design_content.
2026-06-12 23:28:04 +08:00
Kayshen-X a30206222b feat(web): daemon-backed chat/codegen/live-sync, a11y mirror, kit browser, bundle export
Real chat streaming (echo stub retired; production bundle now builds with
codegen), live_sync glue for browser<->daemon<->MCP, codegen panel actions,
structure-bundle zip (stored-zip encoder), iconify web search, component
browser dispatch, accessibility DOM mirror v1, IME + clipboard paths.
2026-06-12 23:28:03 +08:00
Kayshen-X 4bd439a007 feat(desktop): chat transports, discovery, intent routing, IME, export painter, host pumps
OpenCode SSE transport rewrite, Codex/Gemini subprocess quirks port, Claude
token streaming + image prompts, chat intent classify/modify routing, model
discovery + provider probes, image search/generate hosts, kit io +
persistence, theme preset host, live screenshot + scene-painter export
unification, raster size caps, IME cursor-area anchoring, web canvas
server seams.
2026-06-12 23:28:02 +08:00
Kayshen-X cdfb7d9596 feat(ai): provider trait + ACP session options batch
Copilot binary constants fix, ACP NewSessionOptions (mcpServers + system
prompt meta), attachment fields on the chat turn surface.
2026-06-12 23:26:39 +08:00
Kayshen-X 994b55f928 feat(native): host dispatch batch — pen/path press, IME routing, panel dispatchers, font enumeration
pen_press + path-edit dispatch, ime.rs preedit/commit routing with chat
anchor, font_picker/image_panel/kit dispatch modules, panel-history undo
coverage tests, geometry split (settings-hover sibling), corner-radius
image clipping + skia text italic caches. variables_panel_* excluded
(concurrent WIP).
2026-06-12 23:26:38 +08:00
Kayshen-X c5b72ddffc feat(editor-ui): canvas + panel widget batch for TS parity
Path-edit overlays + anchor context menu, styled text runs/justify painter,
clipContent clipping, remote-image registry + rounded placeholders, font
family picker, image node section (search/generate popovers), component
browser kit strip/picker, IME preedit overlay, chat attachments UI, kit
management surfaces, preset menu widget. Includes the workspace fmt sweep.
2026-06-12 23:26:37 +08:00
Kayshen-X da3b029bc7 feat(editor): TS-parity engine batch — refine passes, atomic command batch, path editing, paste anchoring, IME state, kit model, web-sync seam
Render-time $variable/ref resolution, design-refine deterministic passes,
EditorCommand::Batch with document-only allowlist + snapshot rollback,
pen/bezier path_edit model, TS paste anchoring (container/sibling/instance
quirk), ime_state for native preedit, uikit kit-file plumbing, web_sync
protocol core. Child coords are parent-relative: translate_subtree now
shifts the root only.
2026-06-12 23:25:38 +08:00
Fini 2cd197a7ec test(ai): ab-v9 manifest matrix harness
scripts/ab-v9/run_matrix.py runs the ab-v3 corpus (52 prompts) through
the full Rust orchestrator per provider (op-smoke headless,
OPENPENCIL_MANIFEST=1) and scores M3 expected-shape (required roles in
the saved .op tree) + M5 element selection, appending rows per cell for
crash-safe resume. Keys come from env only (MM_KEY/ARK_KEY/DS_KEY).

op-smoke grows OPENPENCIL_SMOKE_KEEP_THINKING=1 to keep MiniMax
reasoning ON: ab-v9 showed M3-nothink emits lazy minimal manifests
(17%, ~10s answers) while M3-with-thinking lands 60% with composite
tied-best at ~110s — the MiniMax production routing target.
2026-06-10 21:04:07 +08:00
Fini 4bbf6b0883 feat(ai): element manifest pipeline for the built-in agent
Weak models stop tool-calling 188 element schemas and instead emit a
JSONL element manifest — one {"el":"stat_card",...} declaration per
line. Nesting uses manifest-local line numbers ("in"), node ids are
system-assigned (the id-hallucination class disappears at the protocol
level), and a repairing argument layer replaces strict rejection:
enum synonyms, schema-driven placeholders for missing required params,
plain-string-to-JSON shape coercion, and a bounded second-chance retry
when a builder names its missing arg. Raw PenNode lines stay available
as an escape hatch and raw frames can serve as "in" containers.

- op-mcp: element_manifest.rs — build_element facade over
  semantic_alias_node, kind normalization (prefers theme-aware _v1,
  light default until palette seeding lands), schema-generated prompt
  catalog; every known kind builds from empty args (the never-reject
  guarantee, covered by a 94-kind fixture test)
- op-orchestrator: manifest.rs parser (line-tolerant, id injection for
  raw subtrees, depth-clamped sections) wired into run_subtask behind
  OPENPENCIL_MANIFEST=1; retry ladder falls back to the raw-JSONL path
- op-ai-skills: element-manifest skill (priority 0, replaces the
  jsonl-format skills when active) with anti-hand-roll teaching;
  build.rs adds rerun-if-changed so include_dir! sees new skill files
- subagent.rs: childless rectangles count as content — skeleton-screen
  designs no longer reject as blank

ab-v9 (52-prompt corpus, full orchestration): ark-code-latest and
glm-5.1 hit 85% expected-shape success vs the 58% tool-calling
baseline, at 5-8k prompt tokens per call vs ~19.9k.
2026-06-10 21:03:46 +08:00
Fini 20a50eb70b fix(mcp): emit numeric font size in system-mode toast
add_toast_v1's system branch put the $type-body-size token ref into
fontSize, a strict f64 schema slot — every system-themed toast failed
PenNode deserialization. Emit 14 in every mode (the ref resolves to the
same default at render time; see the fidelity caveat on
build_modal_shell). gap keeps its $spacing-2 ref — that slot accepts
expressions.
2026-06-10 21:02:53 +08:00
Fini 6f2eefed5e refactor(editor): split chat panel paint tests under the 800-line cap
ai_chat_panel/tests.rs had grown to 960 lines. Move the paint-assertion
tests + the recording PanelPaintBackend into a tests_paint.rs sibling
(369 lines), leaving layout/hit-test in tests.rs (599 lines); shared
helpers stay in tests.rs as pub(super).
2026-06-10 21:02:42 +08:00
Fini 79f2a13ae1 fix(editor): restore chat toolbar chrome polish
- run the divider above the input across the full panel width
- paint the built-in model key with the real lucide Key glyph instead
  of a hand-rolled ring+shaft approximation
- concurrency chip rests as a faint ghost at 1x and gets a
  primary-tinted chip when the agent team is staffed, keeping the
  footer hover + cycle wiring
- attach/send are ghost icons; send fades to muted-foreground/30 when
  there is nothing to send

Re-lands 94b9aa1b (dropped during a re-batch) merged with the
agent-team footer layout.
2026-06-10 21:02:21 +08:00
Fini 09e1f5f606 fix(editor): clear agent indicators the instant a design turn stops
Stopping a turn or starting a new chat drops the DesignSession, but the
canvas indicators only cleared when the worker thread next touched its
channel and unwound — which lags seconds behind when the worker is
mid-LLM-call. The breathing borders lingered on a canvas the user had
already moved on from.

Give the host (which owns the turn lifecycle) the indicator epoch:
DesignSession::start mints it (clearing the prior turn at once) and the
session's Drop ends it immediately via end_if_epoch. The worker registers
under the same epoch via Orchestrator::with_indicator_epoch; headless and
test callers pass none and the concurrent path mints its own, so run()'s
signature and the DesignRequest construction sites are untouched.

end_if_epoch clears AND retires the epoch (vs clear_if_epoch which only
clears), so a worker still in its add_frame loop when the turn is stopped
can't re-populate the set under the now-stale epoch. It's epoch-scoped, so
a newer turn that already began is left untouched.
2026-06-10 11:18:38 +08:00
Kayshen-X 56e55f1159 fix(ai): align chat input hit testing with painted text 2026-06-10 00:08:04 +08:00
Kayshen-X 86cb4c3fb8 chore(editor): checkpoint chrome WIP + web picker select-all wiring
Snapshots the full working tree: web select-all picker wiring
(op-host-web) plus in-progress chrome work (chat input rework,
agent settings, codegen panel, variables modal, toolbar actions,
model discovery).
2026-06-09 23:27:39 +08:00
Kayshen-X b1f9b68dbc feat(editor-ui): paint select-all highlight on icon/component search, rename, and canvas text inputs 2026-06-09 23:27:38 +08:00
Fini ad0d795d52 chore: add cargo dev aliases for desktop hot-reload + fast UI tests
dev-desktop wraps cargo-watch to rebuild + relaunch op-host-desktop on
save; test-ui runs the windowless op-editor-ui geometry tests for a fast
inner loop. Both are opt-in conveniences (cargo-watch is a local
install) and don't affect the build.
2026-06-09 21:50:56 +08:00
Fini 98de32baac fix(editor): scope agent-indicator registration + cleanup to a run epoch
The agent-team canvas indicators are a process-global registry shared by
the design worker (which registers them) and the paint pass (which reads
them). Two ways a stale/cancelled run could corrupt the run that
replaced it:

1. Teardown — the host cleared the registry unconditionally, so an old
   run finishing late wiped a newer run's live indicators.
2. Registration — add_frame did no epoch check, so an old worker still
   in its registration loop after a newer begin() folded its frames into
   the new run's registry, leaving stale indicators that only cleared
   when the new run ended.

Stamp each run with an epoch (begin()), kept inside the registry mutex.
Every registration (add_node/add_frame/mark_preview/clear_preview) and
the RAII teardown guard compare the epoch and mutate under the same
lock, so anything from a superseded run is dropped on the floor and a
begin() racing in between can't slip through the gap. The redundant
host-side clears are removed — the worker owns the lifecycle. At most
the latest run ever has live indicators.
2026-06-09 21:50:39 +08:00
Fini 4c0d2af862 fix(editor): make the agent badge opaque so contrast holds in any theme
The badge filled at 0.92 alpha, so in light theme it composited over the
pale canvas and lifted the real background luminance past the contrast
crossover — white-on-purple stopped being legible. Fill opaque so the
foreground pick matches what is actually drawn.
2026-06-09 15:06:38 +08:00
Fini 276b9038b5 fix(editor): use WCAG luminance for agent badge contrast
The perceptual-luminance threshold mis-classified coral (#FF6B6B) as
dark and gave it unreadable white text. Switch to gamma-corrected WCAG
relative luminance with the standard 0.179 crossover: every palette
colour but the dark purple now takes dark glyphs. Test pins all six.
2026-06-09 15:06:37 +08:00