Commit graph

1930 commits

Author SHA1 Message Date
Fini 9e9cdec7cf feat(smoke): OPENPENCIL_SMOKE_PROGRAM mode runs a batch_design program headless
Reads a program file, runs it through op_mcp::batch_design_snapshot, applies, saves
the .op (postProcess off = raw structure) — the headless harness for benchmarking
the program-DSL path vs flat JSONL across weak models.
2026-07-02 21:21:41 +08:00
Fini b43cee87e5 feat(orchestrator): program-DSL generation protocol (parent-by-reference)
OPENPENCIL_PROGRAM_GEN makes the sub-agent emit a batch_design program
(binding=I(parent,{...})) instead of flat _parent JSONL; nesting by captured
binding makes weak-model row decomposition / header-only tables near-inexpressible.
Runs the existing op_mcp executor to a section forest. Gated to the full first
attempt; drops the conflicting jsonl-format skill so PROGRAM_FORMAT governs alone.
2026-07-02 21:21:40 +08:00
Fini 618f60df37 fix(mcp): harden batch_design DSL parser against weak-model JSON typos
split_operations now groups by operation-start grammar + bracket depth (not a
quote/bracket state machine), so a stray unbalanced quote can no longer swallow
following operations. parse_json_arg gains lenient repairs for fused close-quote+
comma, missing opening quote on a string value, and unclosed trailing brackets;
normalize_node_shape drops an empty stroke (0-length PenStroke) instead of failing
the whole node. +5 regression tests (369 pass).
2026-07-02 21:21:39 +08:00
Fini b29e50b632 fix(ai): add connect + overall timeouts to builtin LLM HTTP client 2026-07-02 21:21:38 +08:00
Fini b7deb369dc feat(orchestrator): app-shell content gutter + sidebar footer sink 2026-07-02 21:21:37 +08:00
Fini 7956595853 feat(orchestrator): table-repair post-pass + thread root id through cleanup
Weak models emit a table as a header row followed by FLAT row-indexed sibling
cells (R1 Client Cell, R1 Visit, …, R2 Client Cell, …) that render stacked
vertically with full-width status bars. table_repair::regroup_flat_table_rows
groups them into Table→Row→Cell with header-aligned column widths. Detection is
narrow and never guesses (adversarial review caught heuristic-header /
chunk-of-N over-firing on toolbars/feeds): it requires an explicit table header
AND every cell to carry an R{n} row index, aborting on any ragged/ambiguous run.

ReplaceSubtree allocates a fresh root id, so the structural restructures
(app_shell + table_repair) ran via a new apply_root_transform helper that
returns the current root id; run_cleanup_passes threads it into the subsequent
per-root passes instead of the stale id (which they'd otherwise no-op on).
2026-07-02 21:21:36 +08:00
Fini 46fe45a5b0 feat(orchestrator): app-shell restructure for flat sidebar dashboards
Weak models emit a desktop dashboard's sidebar either as a full-width band on a
vertical root or crammed into a horizontal row with every section — both render
broken (the removed bespoke scaffold used to pre-build the two-column root).
app_shell::reshape_sidebar_to_app_shell detects a sidebar dashboard and rewrites
it to a horizontal [sidebar(260) | content-column(fill)] shell, run in the shared
cleanup::run_cleanup_passes finalize point (covers orchestrator + agentic loop).
A layout==vertical|none guard on fix_horizontal_overflow stops it re-widening the
narrowed sidebar. Detection is hardened (strong sidebar token + structural
dashboard-content gate) against restaurant/landing/top-nav/mobile/multi-screen
false-positives; 14 unit + 1 integration test, verified end-to-end via op-smoke.
2026-07-02 21:21:35 +08:00
Fini e830759cab fix(ai): classify product-noun prompts as Design intent
classify_intent matched only creation verbs, so a noun-phrase request like
"Luxury webapp for managing barbershop clients" fell through to the weak chat
loop instead of the orchestrator. Add product/app nouns (webapp/web app/website/
app for/mobile app/admin panel/saas + 网站/网页/小程序/后台) to DESIGN_KEYWORDS.
2026-07-02 21:21:34 +08:00
Fini a4c71ea2c3 fix(ai): disable thinking for reasoning models on design turns
Reasoning models (glm-5.x / minimax) burn their whole token budget on hidden
<think> and emit an empty design when thinking is left on (glm-5.2: thinking≈30k,
text=0). design_turn_thinking_mode forces ThinkingMode::Disabled for any model
whose profile is thinking_disabled, applied across all design-capable paths —
the design-agent loop, the builtin tool-executing chat loop, and sub-agent
spawns. Claude (thinking productive) keeps the chat default.
2026-07-02 21:21:33 +08:00
Fini 4be2355174 chore(render-parity): SSIM/bbox/ΔE per-node diff harness
diff_nodes.py computes windowed-SSIM + bbox-hit + ΔE76 + color_de per node and
classifies each as PASS / PAINT / LAYOUT; prep_parity.sh drives pen2op→.op→
render-shots vs Pencil export_nodes baselines.
2026-07-02 21:21:32 +08:00
Fini fb2ebb62ac fix(loader): .op render-parity — fixed-height clip, status-bar box, path geometry
A clipped frame with an explicit numeric height now honours that height and
clips overflow (layout_repair no longer lets the root grow to content), matching
Pencil's fixed-height artboards. Status-bar shell strokes are suppressed in the
scene path (width-independent) so they don't paint a stray black frame, and
legacy .op path nodes remap geometry→d so authored paths aren't dropped.
2026-07-02 21:21:31 +08:00
Fini 0730e1ccce feat(host): headless render-parity tooling — bundled fonts, margin env, layout dump
Bundle 11 OFL design-font TTFs and register them with jian-skia at startup so
--render-shots reproduces Pencil's glyph metrics without system fonts.
OPENPENCIL_RENDER_MARGIN tightens the export crop to match Pencil export_nodes
(no frame), and OPENPENCIL_DUMP_LAYOUT prints every node's computed rect as JSONL
to diff our layout against Pencil snapshot_layout element-for-element. Bumps
vendor/jian to the bundled-font + Auto=no-wrap render-parity commits.
2026-07-02 21:21:30 +08:00
Fini c179fd2837 refactor(orchestrator): simplify — remove planning mode-rotation ladder, concurrent multi-screen path, and dashboard bespoke scaffold (−6.9k lines)
Data verdict (copy-pencil-verdict.md): weak-model M3 quality comes entirely from the
SEQUENTIAL deterministic core (manifest element-builders + role-resolver + post-passes
+ finalize), exercised at concurrency=1. The 3 scaffold strategies / mode-rotation /
per-subtask retry ladder are removable complexity not paid for by M3. Collapsed to a
single sequential path; concurrent (perf-only) folds to sequential; dashboard folds into
the generic path (cleanup_desktop_dashboard already handles sparse rows). Kept the
deterministic core 100% intact + BufferDocSink/clamp_concurrency (spawn_agents) + the
dashboard normalizer trio (feeds plan_normalize). M3 gate held within noise (50%→ the one
flip re-ran 2/3 PASS; 7/8 prompts identical; no new failures from removed code).
2026-07-02 21:21:29 +08:00
Fini cd2131ce28 feat(smoke): minimal scaffold seed for loop (OPENPENCIL_SMOKE_LOOP_SEED) reusing build_fallback_plan; data-gate harness for orchestrator-vs-loop migration 2026-07-02 21:21:28 +08:00
Fini 958c544293 feat(ai-skills): design-agent loop teaching prefers emit_elements (high-level element kinds) over raw batch_design primitives 2026-07-02 21:21:27 +08:00
Fini 03fbc8fbd8 feat(host): emit_elements loop tool — element-manifest builders (el:kind→role-tagged subtree) as a 15th design tool, reusing op_orchestrator::manifest::parse_manifest 2026-07-02 21:21:26 +08:00
Fini 02f31477b9 feat(ai-skills): budget pin for forced skills (trim_by_budget_pinned) + dual-protocol (type:ref/el:ref) component-composition teaching 2026-07-02 21:21:25 +08:00
Fini cc2846d618 feat(orchestrator): force-include component-composition teaching when library present + el:ref/type:ref protocol-branched manifest 2026-07-02 21:21:24 +08:00
Fini 03d7c9b437 feat(mcp): el:ref component-instance kind in Element-Manifest IR (manifest-arm composition → PenNode::Ref) 2026-07-02 21:21:23 +08:00
Fini 0c2fdf8650 feat(loader): merge library masters onto separate Components page (avoids active-page pollution / dashboard scaffold collision) 2026-07-02 21:21:22 +08:00
Fini a67723fbc4 feat(editor-core): append_components_page_masters — design-kit masters on a hidden Components page, active design page stays clean 2026-07-02 21:21:21 +08:00
Fini 77f60a4efb fix(editor-core): ref slot-children fallback — instance inline children fill empty-master shells (Pencil slot-component pattern)
Pencil's slot-component pattern uses an empty styled master (slot:[...] + zero children)
with the instance supplying content via its own inline children. expand_ref only
populated children from the master, dropping instance content → empty shell → blank
white circle in converted templates. Now falls back to instance children (remapped)
when the master has none. Fixes converted-template stat-card rendering + composed-ref
content. +2 ref_resolve tests +1 variables_resolve nested-token regression guard.
2026-07-02 21:21:20 +08:00
Fini 72dbf535d5 chore(editor-ui): chat panel + checklist working-tree progress (WIP) 2026-07-02 21:21:19 +08:00
Fini 5b612ed6c6 feat(smoke): headless agentic-loop mode (OPENPENCIL_SMOKE_LOOP) + design-library loading for benchmarking 2026-07-02 21:21:18 +08:00
Fini 7b1307d72e feat(ai-skills): integrate harvested Pencil guide depth (web-app/mobile/landing/slides/dashboard/design-system) + component-composition + shader-fill teaching 2026-07-02 21:21:17 +08:00
Fini c80f43dbf5 feat(desktop): chat-session loop bridge (finalize/spawn) + smoke library load + image downscale 2026-07-02 21:21:16 +08:00
Fini ed8f763af4 feat(host): agentic-loop screenshot/finalize/spawn bridge + real vision providers + smoke library env 2026-07-02 21:21:15 +08:00
Fini 31ca7c1168 feat(orchestrator): loop-finalize backstop + concurrent spawn-agents + vision validation providers + component-manifest prompt 2026-07-02 21:21:14 +08:00
Fini 89fbee2095 feat(editor-core): mesh/shader fill state + ref id-remap + chat-session state 2026-07-02 21:21:13 +08:00
Fini 41f46ff0d2 feat(mcp): batch_design ref-node emission + full PenFill passthrough + set_node_stroke_side_width tool + get_editor_state 2026-07-02 21:21:12 +08:00
Fini 8adb09220c fix(lint): typography detector adjustment 2026-07-02 21:21:11 +08:00
Fini e6c14f9550 feat(render): skia mesh-gradient via draw_vertices + SkSL shader paint (shader_cache) 2026-07-02 21:21:10 +08:00
Fini bf4a741d8e feat(loader): mesh/shader fills + .pen→.op legacy normalize hardening + pen2op bin + design-library merge
Bumps jian submodule for mesh-gradient/shader PenFill variants. normalize_legacy_doc
gains 8 .pen-compat repairs (stroke-fill string, gradient fill, icon/prompt nodes,
$ref cornerRadius, single-object fill). New pen2op bin converts Pencil .pen→.op.
library.rs merges a .lib.op's reusable masters+variables into a working doc.
2026-07-02 21:21:09 +08:00
Kayshen-X 89e5699e69 fix(ai): chat panel hover/close/send-slot refinements (#41/#42/#43)
- #41: collapse chevron renders through IconButton so it shows the ghost
  button-hover wash instead of only swapping the icon color
- #42: send/stop share one circle slot (toggle in place); footer cluster
  sits snug with no reserved stop gap; hit-test routes streaming->stop else send
- #43: example cards stay clickable without a connected model (clicking one
  fills the input; sending still requires a model)
- tab close glyph shows only while the tab is hovered (inset still reserved
  on the active tab so the title doesn't reflow)
2026-07-02 21:21:08 +08:00
Kayshen-X fc58a4601d chore: bump jian submodule (node promotion for batch_design) 2026-07-02 21:21:07 +08:00
Kayshen-X a7d73ebb62 feat(ai): pencil-style agentic design tool-loop, multi-chat tabs, #27 panel restyle
Built-in design generation now runs as an agentic MCP tool-loop (reusing the
agent-rs BuiltInProvider), gated behind OPENPENCIL_DESIGN_AGENT_LOOP / the
Settings experimental toggle; the orchestrator stays the default.

- design-agent system prompt + in-process design toolset (parity-locked with
  the MCP surface) + flag-gated Intent::Design routing
- spawn_agents execution as sequential sub-loops + live creation-mode badges
  (per-agent glow + 'N/M designing...' header)
- new MCP tools: get_guidelines, ToolSearch, get_screenshot, get_editor_state,
  export_nodes, spawn_agents; style-guide local audit
- #27 AI panel restyle: rounded tool cards + green check-rings, gray user
  bubbles, model-pill bottom toolbar, header, empty-state pills, the
  PARALLEL AGENTS (agent_team_size) 1x-6x chip dropdown
- multi-chat tabs: ChatSessions model (Deref-to-active) + tab row UI
  (switch / close / + / Cmd+T) with each run bound to its tab

Large checkpoint commit spanning the working tree (Rust shell crates).
2026-07-02 21:21:06 +08:00
Kayshen-X 2ccb063b28 feat(ai): drain the generation overlay gracefully when a design turn ends
On natural completion the design-turn teardown now calls
agent_indicators::finish_if_epoch instead of end_if_epoch: the already
queued reveals keep playing at the queue cadence and the whole overlay
(cursor + borders) clears itself once the last one lands, so the tail of
a slow 160ms stream is no longer snapped away mid-reveal.

A user stop / abort still tears down immediately via end_if_epoch, so a
cancelled generation does not keep animating. Wired across the
orchestrator run guard, the web design session, the host-core
DesignSession drop, and the desktop sub-agent / design-loop teardown.

Updates the desktop lifecycle tests to match: the frame-clear test now
drives past the drain window before asserting the overlay cleared, and a
shared registry test-lock serializes reveal-streaming turns against the
exact animation-deadline assertion (the registry is process-global).
2026-07-02 21:21:05 +08:00
Kayshen-X 05986b1eab feat(canvas): animate AI design generation with an agent pointer cursor
Each agent gets an arrow cursor that flies between the nodes it places
along the reveal schedule, arriving as each node scale-pops in; the
element currently being placed carries a breathing border. Replaces the
old dashed-border reveal fade (canvas_agent_overlay removed).

Reveal cadence is slowed to a uniform 160ms queue and retained for the
whole run, so the cursor parks on the last placement between streamed
chunks instead of fading out. Splits agent_indicators tests into a
sibling file to stay under the 800-line cap.
2026-07-02 21:02:27 +08:00
Kayshen-X ad52b1386b ci(wasm): install pinned modern binaryen instead of apt v108
The WASM bundle build (#56) and op-web-sdk bundle workflows install binaryen
via apt, which on the ubuntu runner is v108 (2022) — too old for rustc 1.94's
wasm feature set. It lacks the --enable-bulk-memory-opt flag (the original
'Unknown option' failure) AND cannot validate the memory.copy/fill opcodes
rustc now emits, so wasm-opt rejects the bundle with 'all used features should
be allowed'. Download a pinned binaryen version_123 release (matches the local
dev toolchain) and prepend it to PATH. Verified locally: the full
check-wasm-bundle.sh pipeline passes with binaryen 123 against a fresh
rustc-1.94 wasm build.
2026-07-02 02:05:42 +08:00
Kayshen-X 09f2f55f6b fix(ci): rustfmt, clippy -D warnings, and stale test fixes for green rust-check
The rust-check workflow's cargo fmt --all -- --check failed on 108
line-wrap drifts under the pinned 1.94 rustfmt; running cargo fmt --all
clears them. With fmt fixed, the downstream steps (never reached in CI
before) surfaced accumulated lint + test debt from the recent chat-panel
(#41/#42/#43), agentic-design tool-loop, and multi-chat-tab work:

- clippy -D warnings: question_mark, field_reassign_with_default (test-only,
  false positives on DerefMut writes), dead_code, double_ended_iterator_last,
  doc_overindented_list_items, module_inception, single_match, nonminimal_bool,
  sliced_string_as_bytes — fixed via clippy's own mechanical rewrites or
  narrowly-scoped #[allow] on test items.
- op-editor-ui: the no-model quick-action-card test asserted pre-#43 behavior
  (pills are now clickable regardless of model); re-point it at the Example hit.
- op-host-native (gl-host) + op-host-web (canvaskit) widget_host tests: 10
  stale UI/layout/behavior expectations — footer gained a palette icon
  (attach shifted), quick-action pills are full-width stacked, the speed chip
  opens the Parallel-Agents picker (#32), applying a single-root-frame design
  swaps the empty starter frame (command_root_replace) so the child count is
  unchanged, a CJK prompt wraps to two lines, the toolbar grew under the
  bottom-left chat panel, and the canvas Preview button is behind the
  experimental-features opt-in. All test-only; the two bug-suspect cases (CJK
  selection, design-apply count) were confirmed intended behavior.
- op-host-web canvaskit test helper returned ChatState where the .chat field
  is now ChatSessions (multi-tab); return the container and let DerefMut carry
  callers.

No production behavior changed.
2026-07-02 01:54:05 +08:00
Kayshen-X 6a43c90774 build(ci): binaryen-tolerant wasm-opt flags + refresh cargo-deny advisories
The wasm bundle gates (tools/check-wasm-bundle.sh and
crates/op-web-sdk/tools/build-wasm.sh) hard-passed --enable-bulk-memory-opt
to wasm-opt, which older binaryen (the CI runner's apt package) does not
recognize, failing the WASM bundle build (#56) and op-web-sdk bundle
workflows at the size gate. Probe wasm-opt --help and keep only the feature
flags the installed binaryen advertises; on those older versions the single
--enable-bulk-memory already covers memory.copy/fill, so dropping the unknown
flag is safe. Local binaryen (v117+) keeps both.

cargo-deny advisories also failed: ttf-parser flagged unmaintained
(RUSTSEC-2026-0192, a transitive font-stack dep with no maintained
replacement) and memmap2 flagged unsound (RUSTSEC-2026-0186). Ignore the
former and bump memmap2 0.9.10 -> 0.9.11 (the patched release) for the
latter. advisories now pass.
2026-07-02 01:53:40 +08:00
Kayshen-X 22da4eed3c chore(repo): retire agent-native; root is now a pure Cargo workspace
- Remove the Zig `agent-native` git submodule (no Rust crate depends on it;
  the built-in agent runtime is the Rust `agent` crate under vendor/agent).
- Make the repo root a pure Cargo workspace: delete root package.json + bun.lock;
  move all web-SDK JS/Bun tooling into packages/ (new packages/package.json
  workspace root, generate-iconify-catalog.mjs, and the oxlint/oxfmt configs).
- Scrub agent-native from all docs and fix README dev commands + prerequisites
  to reflect the Rust product (cargo directly; bun tooling runs from packages/).
- Drop the deleted-root-package.json read from the op-host-web ci_workflow test.
2026-07-01 22:16:04 +08:00
Kayshen-X 77dca8c01b chore: retire TypeScript OpenPencil, delete apps/* + pen-* packages
The product is now Rust (crates/) + the Zig agent runtime
(packages/agent-native) + the wasm-backed web SDK (packages/op-web-sdk*).
Delete the retired TypeScript editor/desktop/CLI (apps/*), the pen-*
packages, and their orphaned TS tooling, Dockerfile, and root tsconfig.

Rust-side hooks into the deleted TS are rehomed so the workspace still
builds, tests, and releases green:
- op-mcp: vendor the 10 element-tool-defs shards it include_str!'d from
  pen-mcp into crates/op-mcp/assets/element-tool-defs/ (git renames), and
  repoint the compile-time includes + the runtime parity test's read_dir.
- op-orchestrator: reword the parity panic that named the retired
  dump-planner-golden.ts generator (goldens stay as frozen baselines).
- CI: drop the TS-derive golden-drift + planner-parity oracle jobs and the
  TS path filters from rust-check.yml; repoint the cargo-bundle icon in
  rust-release.yml to crates/op-host-desktop/assets/icon.png.
- Release (Windows): recover the deleted apps/desktop/build/icon.ico into
  crates/op-host-desktop/assets/icon.ico and repoint the NSIS installer
  (rust-release.yml /DICON_FILE + package-windows.nsi ICON_FILE fallback +
  its example invocation), so the Windows release build still finds it.
- Remove the dead .githooks/post-commit hook — it rebuilt the deleted
  out/mcp-server.cjs via the removed mcp:compile script and only watched
  now-deleted pen-* paths; the Rust MCP is built by cargo.
- Recover apps/web/public/logo-discord.svg to screenshot/ and repoint the
  15 READMEs' logo/link paths.

package.json is now Rust-first (dev/build/test -> cargo + serve-web) and
docs (CLAUDE.md/AGENTS.md/packages+crates CLAUDE.md) describe the Rust
product. The retired TS remains recoverable via git (last tag v0.7.5).

Verified: cargo check --workspace green; cargo test -p op-mcp 353 passed;
cargo test -p op-orchestrator 848 passed; cargo test --workspace --no-run
compiles all targets; rust-release.yml parses and references no deleted
build assets.

Pre-commit fmt hook bypassed: its cargo fmt --check is pre-red from a
repo-wide stable-vs-nightly rustfmt config drift affecting unrelated files;
the .rs files touched here produce no fmt diff.
2026-07-01 21:12:39 +08:00
Kayshen-X a4ee78ba86 fix(ai): chat panel hover/close/send-slot refinements (#41/#42/#43)
- #41: collapse chevron renders through IconButton so it shows the ghost
  button-hover wash instead of only swapping the icon color
- #42: send/stop share one circle slot (toggle in place); footer cluster
  sits snug with no reserved stop gap; hit-test routes streaming->stop else send
- #43: example cards stay clickable without a connected model (clicking one
  fills the input; sending still requires a model)
- tab close glyph shows only while the tab is hovered (inset still reserved
  on the active tab so the title doesn't reflow)
2026-06-25 22:40:48 +08:00
Kayshen-X d603f2f388 chore: bump jian submodule (node promotion for batch_design) 2026-06-25 00:15:55 +08:00
Kayshen-X b1aebc3252 feat(ai): agentic design tool-loop, multi-chat tabs, #27 panel restyle
Built-in design generation now runs as an agentic MCP tool-loop (reusing the
agent-rs BuiltInProvider), gated behind OPENPENCIL_DESIGN_AGENT_LOOP / the
Settings experimental toggle; the orchestrator stays the default.

- design-agent system prompt + in-process design toolset (parity-locked with
  the MCP surface) + flag-gated Intent::Design routing
- spawn_agents execution as sequential sub-loops + live creation-mode badges
  (per-agent glow + 'N/M designing...' header)
- new MCP tools: get_guidelines, ToolSearch, get_screenshot, get_editor_state,
  export_nodes, spawn_agents; style-guide local audit
- #27 AI panel restyle: rounded tool cards + green check-rings, gray user
  bubbles, model-pill bottom toolbar, header, empty-state pills, the
  PARALLEL AGENTS (agent_team_size) 1x-6x chip dropdown
- multi-chat tabs: ChatSessions model (Deref-to-active) + tab row UI
  (switch / close / + / Cmd+T) with each run bound to its tab

Large checkpoint commit spanning the working tree (Rust shell crates).
2026-06-25 00:12:45 +08:00
Fini 541da7bcb7 test: adapt cleanup + chat-session tests to origin's rebase
op-orchestrator:
- import EffectField directly (origin's cleanup.rs no longer re-exports it
  via `use super::*`)
- insert both concurrent-cleanup roots in one InsertSubtree, since origin's
  command_root_replace now replaces an empty root on single-node top-level
  inserts (two sequential empty inserts would collapse to one child)
- defer the bottom-nav upward-shadow assertion pending reconciliation with
  Kayshen's e3ed2f1e "normalize mobile bottom tabs" (top-navbar transparency
  assertion retained)

op-host-desktop:
- import clear_fresh_starter_frame_for_design via `super::launch::` so the
  retained starter-frame tests resolve it after the merge
2026-06-21 23:18:23 +08:00
Fini d353a58450 chore: bump jian submodule (image cover + leaf flex-shrink) 2026-06-21 23:18:22 +08:00
Fini d517c0a2c0 chore(ai): smoke concurrency override + ab-v9 matrix 2026-06-21 23:18:21 +08:00
Fini ea3f94093c fix(editor): desktop chat session + builtin http handling 2026-06-21 23:18:20 +08:00