Commit graph

2530 commits

Author SHA1 Message Date
Fini 322ae23760 feat(editor): drop an image file onto a node to set its fill
Dropping a png/jpg/webp used to be silently ignored — placing a
screenshot meant importing, dragging into position and matching sizes
by hand. Now a drop resolves the deepest fillable node under the
cursor (walking up past text and icons), writes a cover image fill in
one undo step, and rings the target while hovering so the outcome is
visible before release. Empty-canvas drops insert an image node at the
point; document drops keep their open/import behavior. Drag positions
come from an AppKit probe on macOS; other platforms degrade to a
centered insert.
2026-07-28 00:29:39 +08:00
Fini 80d9b2aca3 feat(agent): surface a quality credential after generation
The cleanup passes and blocker detectors already run on every
generation, but their work was invisible: problems produced nudges
while a clean result said nothing. Count each accepted document edit
per check category through a DocSink decorator (pass bodies untouched),
carry the tally through loop finalize and the orchestrator's progress
events, and render an honest completion line — categories actually
run, repairs actually applied, open issues never papered over. A run
with nothing to fix still earns its positive credential; a turn that
checked nothing reports nothing.
2026-07-28 00:29:39 +08:00
Fini 1ab8c0cf01 fix(editor): advance the document revision in canvas drag mutators
The layout-scene cache keys on a revision counter, so any mutator that
edits the tree without bumping it leaves the canvas painting a stale
scene: handle-resize, rotation, pen and path-anchor drags all updated
the document every frame while the cache kept answering 'unchanged',
and the new geometry only appeared after some later click bumped the
counter. Register the change inside each mutator (gated on an actual
write), document the contract on mark_document_changed, and pin it
with an end-to-end test that settles the cache first and then asserts
the painted scene follows the drag within the same frame.
2026-07-28 00:29:39 +08:00
Fini 864753b950 test(desktop): keep persistence tests out of the real user config
Desktop tests exercised agent_connect_store against the real
~/.openpencil, so a parallel test run could leave the user's actual
reconnect list in whichever state the last writer happened to save.
Add a process-level user-root override to op-config-store (a OnceLock
seam, not an env var — set_var races parallel test threads) and a
guard at the desktop store entry points that redirects every test
write to a per-pid scratch root, so isolation does not depend on
which test runs first.
2026-07-28 00:29:39 +08:00
Fini e6667b77c1 fix(desktop): stop failed probes evicting remembered connections
Every probe outcome wrote the connected flags through to agents.json,
so one bad launch — a GUI environment missing the user's shell env, a
machine offline at login — persisted connected=false and removed the
provider from the startup replay list for good; the user had to press
Connect every launch. Treat the store as the last-known-good list:
only successes join it, and an explicit Disconnect is recognized by
the card's phase returning to Idle rather than by the flag snapshot,
which also spares providers still queued for replay. The replay queue
now advances through begin_provider_connect — a bare request-seam
write left the card outside Probing, so the landing hook discarded
the outcome and stranded every provider after the first.
2026-07-28 00:29:39 +08:00
Fini 103cf81217 fix(agent): give networked model probes a budget past the cli's own error
The shared 10s probe budget cut off agy's real failure message, which
takes just over 11s to arrive when the process carries no proxy vars —
the card showed a bare timeout one beat before the actionable 'please
sign in' would have landed. Keep 10s for the local version gate and
give the models step, a network round trip, 20s in both the connect
and discovery chains.
2026-07-28 00:29:39 +08:00
Fini c4300d100b fix(agent): surface the cli's own error instead of 'not responding'
cli_version folded spawn failures, non-zero exits and timeouts into
one None and discarded stderr, so a codex launched without the user's
PATH — whose shebang dies with 'env: node: No such file or directory'
— read as an unexplainable 'Codex CLI not responding'. Return a
structured failure carrying the output tail and word the card message
per cause, draining both pipes on capture threads.
2026-07-28 00:29:39 +08:00
Fini bb46ec68af fix(agent): capture the interactive login shell env for gui launches
The login-shell probe ran 'zsh -lc', which reads .zprofile but not
.zshrc — where homebrew, nvm and proxy exports conventionally live —
so a Dock launch still missed node for shebang CLIs and stalled
networked probes behind a proxy-only route. Switch the probe to -ilc
under a hard 8s deadline (an unbounded interactive rc could hang
startup), and graft an allowlisted set of proxy variables onto the
process alongside PATH, never overwriting values already present.
2026-07-28 00:29:39 +08:00
Fini d3f2f52933 fix(agent): bound pipe capture when a probe kill leaves grandchildren
Killing a timed-out CLI does not close pipes its own children still
hold, so the drain thread's join waited on the grandchild instead of
the deadline — a 400ms probe budget measured 30s wall clock. Replace
drain_pipe with PipeCapture: normal exits still join to EOF, kill
paths take the captured bytes after a short grace instead of joining.
2026-07-28 00:29:39 +08:00
Kayshen-X 693423f2f9 fix(ai): constrain retry replay to failed turns 2026-07-27 21:35:09 +08:00
Adrian Rojas 0748002045 fix(ai): normalize scripted modification nodes 2026-07-27 21:31:17 +08:00
Adrian Rojas c333d85e8b fix(ai): preserve modify context across retries 2026-07-27 21:30:17 +08:00
Kayshen-X 90870370ad refactor: typed error enums across the whole workspace
Completes the stringly-error conversion: 341 remaining
Result<_, String> signatures drop to two documented boundary sites
(a String-compat wrapper consumed across a crate boundary and a
test-only diagnostic helper). Eighty-plus enums follow the
established recipe — one enum per failure domain in a sibling
module, byte-identical Display text, From impls replacing map_err
adapters. mcp_live is fully typed (the screenshot channel included)
and all six temporary String bridges are deleted. The flaky
cli-model-discovery trio is made load-proof: exec'd sleeps so the
probe's kill actually closes the pipes, a serializing test lock,
and an escalating budget with a deadline-boundedness assertion.
2026-07-27 21:09:06 +08:00
Kayshen-X 2f7040cb58 docs: refresh the architecture guide after the dedupe and typed-error campaigns
Adds the campaign stale-path banner (839f474a..d2d8104c), documents
op-util, the shared host-logic module tables, the three input-ladder
spines, the i18n panel-shard key workflow, block_on_anywhere, and the
typed-error recipe; deletes claims the reorg made false (old file
splits, 113-tool count, shell-core paths, five-file property panel).
Every path named was existence-checked against the tree.
2026-07-27 21:08:34 +08:00
Kayshen-X dcf8c3b1b3 fix(desktop): support Wayland image clipboard paste 2026-07-27 21:08:15 +08:00
Kayshen-X 3064554ff4 fix(codegen): preserve generated results across framework tabs 2026-07-27 21:04:23 +08:00
Kayshen-X d2d8104c57 refactor(editor): decompose the three input-ladder god methods into ordered tiers
apply_cursor_move (1141 lines) and both hosts' apply_press (1052/897)
become short spines calling Option-returning tier helpers in sibling
modules, preserving the documented hit-test priority order exactly —
verified mechanically: every tier body is byte-identical to its
original line range after undoing the three systematic transforms,
and the spines invoke tiers in strictly ascending original order.
No file in the workspace exceeds the 800-line cap anymore.
2026-07-27 00:11:49 +08:00
Kayshen-X def6a8bcdd refactor: final 800-line sweep across editor, mcp, services, and tool crates
Pure code motion: twenty-eight remaining oversized modules split into
spine + sibling layouts with re-exports keeping every import path and
test name stable. op-codegen, op-smoke, op-mcp, op-design-lint,
op-host-services, op-host-desktop, op-cli, op-i18n, op-editor-core,
op-editor-ui, and op-pen-loader no longer have any file over the cap.
2026-07-26 22:34:37 +08:00
Kayshen-X 9b988d9620 refactor(editor): finish widget_host unification leftovers and split host files
Agent-settings press logic is single-sourced with an explicit
credential-ownership scope (operator vs browser); the blank-press
blur path uses the full commit chain on both hosts; the marquee
release commit is shared (web was missing the entered-container sync
— a real bug); sixteen inline screen-to-doc conversions route through
one geometry helper; the wall-clock-zero file-menu anchor is verified
safe and documented. Host spines, keyboard, input tests, agent
settings tests, and the skia backend split under the 800-line cap;
press_helpers drops from 837 to 165 lines.
2026-07-26 22:30:15 +08:00
Kayshen-X 83005257cd refactor(editor): single-source widget_host cursor/drag, misc pairs, and spines
Completes the widget_host fork unification: drag commit/preview
policy, image-crop gesture, scroll handlers, cursor-hover flows,
account/a11y/missing-fonts/variables-panel presses, drag-state
structs, and the canvas/overlay geometry (the coordinate invariant
now lives in one file) are all shared between the native and web
hosts. Proven drift fixed with history evidence: native shift-drag
skipped the undo snapshot, native painted two variables menus at once
(stale row-menu clears), commit sequencing dropped drafts on
Resize/Close, and the per-press full-document variable-table walk is
replaced by direct state reads. Intentional platform differences
remain host-side with comments.
2026-07-26 20:32:43 +08:00
Kayshen-X 6c8f41dc0e refactor(mcp,web): typed errors for mcp_serve, export, and batch direct ops
McpServeError separates protocol faults from socket failures;
ExportError carries structured fields with byte-identical Display;
ProgramError gains precise InvalidValue/ValueOutOfRange variants.
Fifteen map_err adapters in the web canvas server collapse into From
impls. The flaky cli model-discovery trio is fixed at the root: the
test scripts now exec their sleep (the forked child used to inherit
the probe's pipes and hold the reader for the full duration) and poll
with a doubling budget, turning an assumed deadline into a proven one.
2026-07-26 20:32:26 +08:00
Kayshen-X 5b996a93b3 refactor(editor): single-source widget_host press, keyboard, and dispatch families
The native/web widget_host twins' press/click, keyboard, and
property/image dispatch layers now share one implementation
(op-editor-core host_*_transitions for pure state, op-editor-ui
press_flow/chat_click_flow/property_panel_dispatch for widget-typed
logic); hosts keep thin platform arms. Proven drift fixed along the
way: web's Interactions actions were silent no-ops, web left font
pickers open behind property popovers, native's image-src writes
skipped the pan-cache invalidation, and FocusEffectParam dropped the
previous draft on native. Intentional platform differences stay
host-side with comments.
2026-07-26 17:18:29 +08:00
Kayshen-X 6f242bd1a8 refactor: split every oversized module into sibling files
Pure code motion across seven crates (orchestrator, host-services,
host-desktop, editor-core, pen-loader, editor-ui, mcp, canvaskit):
spine keeps the public surface, siblings take cohesive clusters,
re-exports keep every import path compiling unchanged. Test counts
are identical before and after per crate; op-orchestrator and
op-host-desktop no longer have any file over the 800-line cap.
2026-07-26 14:58:19 +08:00
Kayshen-X 961a149c8a fix(editor): finish block_on_anywhere rollout and narrow design-ack snapshots
Every remaining private current-thread runtime and bare block_on in
sync code now routes through block_on_anywhere, removing the latent
'runtime within runtime' abort on tokio workers. The desktop design
pump's per-apply-ack full EditorState clone (and the subtask-retry
seed) switch to the narrowed snapshot — chat/codegen/theme_presets
grow with session length and are read by nothing in the worker mirror.
2026-07-26 14:58:12 +08:00
Kayshen-X c188205368 refactor(editor): split editor_ui_state into sibling modules and narrow snapshots
Spine + seven siblings (all under the 800-line cap) with re-exports
keeping every import path stable; three measured field groups become
substructs (preview, size toggles, design-md panel — 192 -> 176 flat
fields; larger clusters rejected by workspace touch-count); MCP and
chat-launch request snapshots drop chat/codegen/theme_presets, which
grow with session length and are read by no consumer.
2026-07-26 13:21:06 +08:00
Kayshen-X 0fc6753dd9 refactor(cli,mcp,web): typed error enums for the densest stringly paths
CliError/SkillInstallError carry every op-cli failure (94 sites),
ProgramError types batch_program (14), WebCanvasError maps route
failures onto their existing HTTP statuses (23 -> 6 deliberate
boundary adapters). Display output is byte-identical to the old
strings so caller-visible text and tests are unchanged.
2026-07-26 13:20:59 +08:00
Kayshen-X 621f30e425 fix(editor): async hygiene — safe block_on, bounded acp channels, thread teardown
One block_on_anywhere helper (block_in_place inside a multi-thread
runtime, shared runtime otherwise, loud failure on a current-thread
runtime where both options deadlock); acp transport channels bounded
at 1024 with reader-safe try_send; a stranded child process + reader
thread leak in model discovery fixed; detached threads either joined
or documented; Antigravity/Grok probe strings localized (catalog 1105).
2026-07-26 13:19:34 +08:00
Kayshen-X bba6f338d6 refactor: dedupe cross-crate code and converge hardcoded literals
New leaf crate op-util single-sources hex-color parsing (9 divergent
copies, one with a non-ASCII panic), JSON escaping (one copy was
lossy), and HTML/XML escaping (one copy missed the quote entity — an
attribute-injection gap). Desktop now delegates image generate/search,
settings payload serde, and the --mcp/--serve-web argv dispatch to
op-host-services / op-editor-host-core instead of carrying drifted
copies. Byte-identical widget_host twin files collapse into shared
op-editor-core host_ui_transitions. Auth routes, the MCP port, product
name, env-var names, service URLs, and status colors move to single
shared constants / theme tokens; the stale claude-sonnet-4-5 default
model id is corrected.
2026-07-26 11:24:22 +08:00
Kayshen-X 02770eb689 feat(i18n): complete locale coverage across menus, providers, and panels
Native menu bar, provider status strings, export dialog, layer panel,
and image-panel popovers now resolve through op-i18n instead of
hardcoded English; the three ad-hoc mini locale tables fold into the
canonical catalogs. New *_panel.rs overflow shards keep every table
under the 800-line cap (catalog at 1098 keys). The desktop menu also
rebuilds live on locale change instead of waiting for the next launch.
Includes the pending interactions/quick-action/dialog locale entries
and locale.rs additions from the working tree.
2026-07-26 11:24:06 +08:00
Kayshen-X 839f474a60 fix(editor): degrade instead of panicking on host failure paths
Poison-tolerant locking in the ACP transport (a panicking reader task
used to brick every later call), checked thread spawns on UI paths
(thread creation fails under fd/memory pressure and took the editor
down with unsaved work), MCP tools return typed errors for malformed
LLM-controlled args, bounded name-suffix loops, and event-driven chat
stream polling instead of a 20ms sleep loop.
2026-07-26 11:23:43 +08:00
Kayshen-X 5e4c62ef14 feat(web): instant sign-in popup with loading interstitial and full account i18n
The SignIn press now opens a same-origin /auth/loading spinner page and
fires the begin request inside the same user gesture; the daemon holds
that request until the pairing's verification URI exists and returns it
inline, so the popup navigates straight to the sso page instead of
sitting on about:blank through a poll cycle. All account/login strings
moved out of hardcoded per-locale matches into the op-i18n tables and
are translated across all 15 locales.
2026-07-26 00:31:04 +08:00
Kayshen-X 656676d0c6 docs: sync installation guide across translations 2026-07-26 00:26:37 +08:00
Kayshen-X ba3f58653e fix(web): don't let the first login-status poll race the begin request
The status poll fired in the same tick as the begin POST and observed
the daemon's pre-begin idle state, which tore the flow down after one
click (leaving only the blank placeholder popup). Polls are now
suppressed while begin is in flight, and idle only ends the flow after
a sustained streak.
2026-07-25 23:59:23 +08:00
Kayshen-X 5eda459423 fix(web): popup wording for the login modal's idle note and button 2026-07-25 23:55:44 +08:00
Kayshen-X 6a780c7425 fix(web): pre-open the sign-in popup in the click gesture and use popup wording
Opening the verification page from the async poll callback was popup-
blocked (the 'click sign-in twice' bug); a placeholder window opened
synchronously inside the press is navigated once the URL arrives, and
closed on cancel/failure. The wasm login modal now says 'popup window'
instead of 'your browser' — the web editor already runs in one.
2026-07-25 23:51:27 +08:00
Kayshen-X 7d3b66e07b fix(desktop): link prebuilt op-auth with -bundle so thin-lto release links
Bundled foreign archive members were fed to thin-LTO and failed with
'failed to get bitcode from object file for LTO'; -bundle defers the
archive to the final link.
2026-07-25 23:44:27 +08:00
Kayshen-X 5c5003e90d fix(desktop): rebuild prebuilt op-auth libraries without lto
The archives previously carried LTO'd objects that broke openpencil's
thin-LTO release link (failed to get bitcode from object file).
2026-07-25 23:44:26 +08:00
Can H. Tartanoglu bb27a7458f
feat(integration): expose declarative harness surface (#185)
* chore(nix): add reproducible OpenPencil flake

* fix(nix): patch and smoke-test prebuilt binaries

* chore(ci): keep workflow validation in integration follow-up

* feat(integration): expose declarative harness surface

* ci: run Nix checks for integration surface

* test: verify all OpenPencil runtime tools

* feat(integration): expose web server package

* chore(nix): remove rebase conflict marker

* fix(nix): update OpenPencil CLI prebuilt hash

* fix(nix): validate source outputs and pin release assets

* fix(nix): refresh desktop release hash

* fix(nix): refresh Bun dependency hash

* fix(nix): normalize Bun hoisted aliases

* ci: make headless desktop smoke test deterministic
2026-07-25 23:44:01 +08:00
Kayshen-X e77355e193 feat(web): unified device login through the serve-web daemon
The wasm bundle ships no auth code: the daemon proxies the device-login
flow over /api/auth/* using the same prebuilt op-auth library and the
same ~/.openpencil/auth credential store as the desktop GUI, so a
session started in either host signs both in. The web shell opens the
verification page in a popup, polls flow progress into the shared login
modal, and re-checks session health every 30s. The proxy refuses
non-loopback binds outside managed mode — the daemon session belongs to
its owner, not to whoever can reach the port.
2026-07-25 23:28:03 +08:00
Kayshen-X 5888b29323 fix(editor): report machine name to sso and drop workspace menu row
The approval page already labels the product and platform, so the
device name must be just the machine (scutil ComputerName / hostname);
the account dropdown's workspace row was a no-op placeholder.
2026-07-25 22:45:26 +08:00
Kayshen-X 16373e2cc2 feat(desktop): prebuilt op-auth library for windows arm64 2026-07-25 22:22:58 +08:00
Kayshen-X d1fef42e0b feat(desktop): prebuilt op-auth library for windows msvc 2026-07-25 19:44:58 +08:00
Kayshen-X 50a6c228a2 feat(desktop): prebuilt op-auth libraries for intel macos and linux
Extends the prebuilt matrix to x86_64-apple-darwin and both linux-gnu
architectures (built against glibc 2.17); the msvc artifact follows the
<name>.lib convention build.rs now resolves per target.
2026-07-25 19:43:20 +08:00
Kayshen-X cacaeefc95 feat(desktop): browser device login through prebuilt op-auth library
The proprietary device-login client (ZSeven-W/op-platform) ships as a
C-ABI static library committed under op-auth-bridge/prebuilt/<target>;
builds without an artifact fall back to an inert stub so any checkout
compiles with login hidden. The desktop host starts the pairing flow
from the sign-in modal, opens the verification page in the system
browser, polls flow status each frame, restores persisted sessions at
startup, and revokes the device token on sign-out.
2026-07-25 19:08:38 +08:00
Kayshen-X 39287ac03d feat(editor): runtime account gate and device-login flow status state
Replace the compile-time ACCOUNT_UI_AVAILABLE release gate with
EditorUiState::account_ui_available so hosts enable the account UI only
when an auth backend is actually linked, and surface device-login
progress (waiting for browser / approval / exchanging / failure) in the
sign-in modal.
2026-07-25 19:08:15 +08:00
Kayshen-X 4702c8e06a test(agent): stop cli probe tests racing process startup
The hung-CLI probe tests gave the deadline 200ms, which a cold exec of a
just-written temp executable can exceed before it prints — the capture
came back empty and the auth-marker assert flaked (2 of 3 isolated runs).
Give the probes a 2s budget, well past spawn cost, so the timeout branch
is reached with the script's output already drained.
2026-07-25 13:09:19 +08:00
Kayshen-X 685c5dd17e docs(release): title v0.8.2 and promote note headings to release names
GitHub releases were named by bare tag because the action got no name.
The note's leading heading is the natural title, so publish it as the
release name and drop it from the body instead of repeating it.
2026-07-25 12:53:31 +08:00
Kayshen-X 898fbd7503 docs(release): cover design agent and canvas perf in v0.8.2 notes
The notes stopped at the 2026-07-23 state and never described the design
agent at all, despite it carrying the largest share of the v0.8.2 work.
Add the multi-screen generation, geometry-repair, provider/skill, and
large-document canvas performance sections, plus the image-crop, stroke
ordering, right-rail, and Windows save changes landed since.
2026-07-25 12:49:50 +08:00
Fini 6bf47c5bbc fix(agent): share timeout diagnostics with model discovery probes
The discovery chain's command_output still discarded captured bytes on timeout, the same defect fixed for connect probes. Extract BoundedProbe and diagnose_timeout into a shared cli_probe_support module so both chains surface auth hints and output tails, and add an exe/timeout seam so timeout paths are testable.
2026-07-25 09:12:37 +08:00
Fini 81d90fc9d4 fix(ai): make skill names unique across the registry
Two skills both declared name: design-system, making get_skill_by_name order-dependent. Rename the knowledge composition skill to design-system-composition (the generation token-architect skill keeps the name every code path references) and pin registry-wide uniqueness with a test. The public get_guidelines topic key is unchanged.
2026-07-25 09:12:37 +08:00